本节书摘来异步社区《Redis实战》一书中的第2章,第2.1节,作者: 【美】Josiah L. Carlson(约西亚 L.卡尔森)译者: 黄健宏 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.1 登录和cookie缓存

每当我们登录互联网服务(比如银行账户或者电子邮件)的时候,这些服务都会使用cookie来记录我们的身份。cookie由少量数据组成,网站会要求我们的浏览器存储这些数据,并且在每次服务发出请求时再将这些数据传回给服务。对于用来登录的cookie,有两种常见的方法可以将登录信息存储在cookie里面:一种是签名(signed)cookie,另一种是令牌(token)cookie。

签名cookie通常会存储用户名,可能还有用户ID、用户最后一次成功登录的时间,以及网站觉得有用的其他任何信息。除了用户的相关信息之外,签名cookie还包含一个签名,服务器可以使用这个签名来验证浏览器发送的信息是否未经改动(比如将cookie中的登录用户名改成另一个用户)。

令牌 cookie会在cookie里面存储一串随机字节作为令牌,服务器可以根据令牌在数据库中查找令牌的拥有者。随着时间的推移,旧令牌会被新令牌取代。表2-1展示了签名cookie和令牌cookie的优点与缺点。

因为Fake Web Retailer没有实现签名cookie的需求,所以我们选择了使用令牌cookie来引用关系数据库表中负责存储用户登录信息的条目(entry)。除了用户登录信息之外,Fake Web Retailer还可以将用户的访问时长和已浏览商品的数量等信息存储到数据库里面,这样便于将来通过分析这些信息来学习如何更好地向用户推销商品。

一般来说,用户在决定购买某个或某些商品之前,通常都会先浏览多个不同的商品,而记录用户浏览过的所有商品以及用户最后一次访问页面的时间等信息,通常会导致大量的数据库写入。从长远来看,用户的这些浏览数据的确非常有用,但问题在于,即使经过优化,大多数关系数据库在每台数据库服务器上面每秒也只能插入、更新或者删除200~2000 个数据库行。尽管批量插入、批量更新和批量删除等操作可以以更快的速度执行,但因为客户端每次浏览网页都只更新少数几个行,所以高速的批量插入在这里并不适用。

因为Fake Web Retailer目前一天的负载量相对比较大——平均情况下每秒大约1200次写入,高峰时期每秒接近6000次写入,所以它必须部署10台关系数据库服务器才能应对高峰时期的负载量。而我们要做的就是使用Redis重新实现登录cookie功能,取代目前由关系数据库实现的登录cookie功能。

首先,我们将使用一个散列来存储登录cookie令牌与已登录用户之间的映射。要检查一个用户是否已经登录,需要根据给定的令牌来查找与之对应的用户,并在用户已经登录的情况下,返回该用户的ID。代码清单2-1展示了检查登录cookie的方法。

代码清单2-1 check_token()函数

对令牌进行检查并不困难,因为大部分复杂的工作都是在更新令牌时完成的:用户每次浏览页面的时候,程序都会对用户存储在登录散列里面的信息进行更新,并将用户的令牌和当前时间戳添加到记录最近登录用户的有序集合里面;如果用户正在浏览的是一个商品页面,那么程序还会将这个商品添加到记录这个用户最近浏览过的商品的有序集合里面,并在被记录商品的数量超过25个时,对这个有序集合进行修剪。代码清单2-2展示了程序更新令牌的方法。

代码清单2-2 update_token()函数

通过update_token()函数,我们可以记录用户最后一次浏览商品的时间以及用户最近浏览了哪些商品。在一台最近几年生产的服务器上面,使用update_token()函数每秒至少可以记录20 000件商品,这比Fake Web Retailer高峰时期所需的6000次写入要高3倍有余。不仅如此,通过后面介绍的一些方法,我们还可以进一步优化update_token()函数的运行速度。但即使是现在这个版本的update_token()函数,比起原来的关系数据库,性能也已经提升了10~100倍。

因为存储会话数据所需的内存会随着时间的推移而不断增加,所以我们需要定期清理旧的会话数据。为了限制会话数据的数量,我们决定只保存最新的1000万个会话。①清理旧会话的程序由一个循环构成,这个循环每次执行的时候,都会检查存储最近登录令牌的有序集合的大小,如果有序集合的大小超过了限制,那么程序就会从有序集合里面移除最多100个最旧的令牌,并从记录用户登录信息的散列里面,移除被删除令牌对应的用户的信息,并对存储了这些用户最近浏览商品记录的有序集合进行清理。与此相反,如果令牌的数量未超过限制,那么程序会先休眠1秒,之后再重新进行检查。代码清单2-3展示了清理旧会话程序的具体代码。

代码清单2-3 clean_sessions()函数

让我们通过计算来了解一下,这段简单的代码为什么能够妥善地处理每天500万人次的访问:假设网站每天有500万用户访问,并且每天的用户都和之前的不一样,那么只需要两天,令牌的数量就会达到1000万个的上限,并将网站的内存空间消耗殆尽。因为一天有24×3600=86 400秒,而网站平均每秒产生5 000 000/86 400<58个新会话,如果清理函数和我们之前在代码里面定义的一样,以每秒一次的频率运行的话,那么它每秒需要清理将近60个令牌,才能防止令牌数量过多的问题发生。但是实际上,我们定义的令牌清理函数在通过网络来运行时,每秒能够清理10 000多个令牌,在本地运行时,每秒能够清理60 000多个令牌,这比所需的清理速度快了150~1000倍,所以因为旧令牌过多而导致网站空间耗尽的问题不会出现。

在哪里执行清理函数? 本书会包含一些类似代码清单2-3的清理函数,它们可能会像代码清单2-3那样,以守护进程的方式来运行,也可能会作为定期作业(cron job)每隔一段时间运行一次,甚至在每次执行某个操作时运行一次(例如,6.3节就在一个获取锁操作里面包含了一个清理操作)。一般来说,本书中包含while not QUIT:代码的函数都应该作为守护进程来执行,不过如果有需要的话,也可以把它们改成周期性地运行。

Python传递和接收可变数量参数的语法 代码清单2-3用到了3次类似conn.delete (*vtokens)这样的语法。简单来说,这种语法可以直接将一连串的多个参数传入函数里面,而不必先对这些参数进行解包(unpack)。要了解关于这一语法的更多信息,请通过以下短链接访问《Python语言教程》的相关章节:http://mng.bz/8I7W。

Redis 的过期数据处理 随着对Redis的了解逐渐加深,读者应该会慢慢发现本书展示的一些解决方案有时候并不是问题的唯一解决办法。比如对于这个登录cookie例子来说,我们可以直接将登录用户和令牌的信息存储到字符串键值对里面,然后使用Redis的EXPIRE命令,为这个字符串和记录用户商品浏览记录的有序集合设置过期时间,让Redis在一段时间之后自动删除它们,这样就不需要再使用有序集合来记录最近出现的令牌了。但是这样一来,我们就没有办法将会话的数量限制在1000万之内了,并且在将来有需要的时候,我们也没办法在会话过期之后对被废弃的购物车进行分析了。

熟悉多线程编程或者并发编程的读者可能会发现代码清单2-3展示的清理函数实际上包含一个竞争条件(race condition):如果清理函数正在删除某个用户的信息,而这个用户又在同一时间访问网站的话,那么竞争条件就会导致用户的信息被错误地删除。目前来看,这个竞争条件除了会使得用户需要重新登录一次之外,并不会对程序记录的数据产生明显的影响,所以我们暂时先搁置这个问题,之后的第3章和第4章会说明怎样防止类似的竞争条件发生,并进一步加快清理函数的执行速度。

通过使用Redis来记录用户信息,我们成功地将每天要对数据库执行的行写入操作减少了数百万次。虽然这非常的了不起,但这只是我们使用Redis构建Web应用程序的第一步,接下来的一节将向读者们展示如何使用Redis来处理另一种类型的cookie。

《Redis实战》一2.1 登录和cookie缓存相关推荐

  1. redis学习(四) 登录和cookie缓存

    <redis实战> 第二章 1.cookie缓存用户信息的两种方式 每当我们登录互联网服务时,这些服务会使用cookie记录我们的身份 .cookie由少量数据组成,网站会要求我们浏览器存 ...

  2. 黑马点评Redis实战(短信登录;商户查询缓存)

    黑马点评 通过一个类似于大众点评的项目了解学习redis在实战项目中的使用,下面是项目中会涉及到的模块: 一.导入黑马点评项目 导入springboot项目,导入sql脚本到数据库,开启nginx,更 ...

  3. 腾讯、阿里、百度高工都点头称赞的“Redis 实战超全笔记”,不看你就亏大发了

    写在开头 如何系统,全面,的学习redis呢? 我的一个程序员朋友,在之前有面试 Java 开发工程师岗位时,居然大部分的面试问题都是关于 Redis 的,他都差点都忘记了自己应聘的是 Java 工程 ...

  4. 不看你就亏了,最新最全的腾讯,阿里、百度、美团等大厂都在用的Redis实战

    不要小看一个redis 任何一家公司的招聘信息都包含一段redis的需求. 不要小看一个redis 你能在互联网搜索到的很多文章都讲错了,面试会有很多坑. 不要小看一个redis 搞懂它是你通向分布式 ...

  5. 腾讯,阿里、百度、美团等大厂都在用的Redis实战,不看你就亏了

    不要小看一个redis 任何一家公司的招聘信息都包含一段redis的需求. 不要小看一个redis 你能在互联网搜索到的很多文章都讲错了,面试会有很多坑. 不要小看一个redis 搞懂它是你通向分布式 ...

  6. Redis(五) - Redis企业实战之短信登录

    文章目录 一.导入黑马点评项目 1. 导入SQL 2. 前后端分离 3. 导入后端项目 3.1 将后端项目导入到 Idea 中 3.2 注意:修改application.yaml文件中的mysql.r ...

  7. js cookie 存储checkbox_[cookie实战记录-1]种下一个cookie

    [cookie实战记录-1]种下一个cookie 引子 cookie ~ 也是前端实际工作中一定会碰到的(哎?为什么要说也呢...) 而且由于前一阵 Chrome 的更新改了关于 cookie sam ...

  8. springboot实战pdf_Java程序员中秋节福利发送:Spring boot+Redis实战文档「PDF」

    中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力:到了节日,则要拼奖金.拼福利.拼假期,还要拼创意.今天,小编为大家也准备了一份中秋节礼物,让我们一起来看看礼物是啥吧! Spring boot文档 ...

  9. Redis实战demo

    Redis实战Demo 说明:本项目来自于学相伴飞哥的Redis教程:https://www.kuangstudy.com/,课程优质,收获很大! 项目gitee地址: https://gitee.c ...

  10. Redis实战 - 09 Redis BitMaps 实现用户签到,统计签到次数,统计签到情况等功能

    文章目录 1. 需求分析 2. 设计思路 3. 用户签到和统计连续签到的次数 1. 签到控制层 SignController 2. 签到业务逻辑层 SignService 3. 测试 4. 按月统计用 ...

最新文章

  1. 【Leetcode】刷题之路3(python版)
  2. Java项目:新闻发布系统(java+Springboot+ssm+mysql+maven)
  3. 8W+文本数据,全景式展现中国教育发展情况
  4. C++ WINDOWS API 如何使用NMAKE和CL编译
  5. 过完年,又不想上班了?
  6. 几种排序与最大K问题
  7. swift3.0 从相册选取或者拍照上传图片至阿里云OSS
  8. mysql 创建表字段长度范围_Mysql的建表规范与注意事项
  9. 他是哈佛计算机博士,却成落魄画家,后逆袭为硅谷创业之父 |人物志
  10. 维护 linux 服务器常用操作命令
  11. 小米电视共享计算机权限,小米电视局域网共享文件 小米盒子局域网共享视频通用方法...
  12. Flex应用性能优化
  13. javaw和java,java,javaw和javaws之间有什么区别?
  14. QTcpSocket
  15. 软件开发生命周期中的设计阶段_软件过程模型|如何进行团队式的软件开发?...
  16. Python基础知识练习(含答案)
  17. Linux 内核软死锁(soft lockup)记录
  18. java金额比较大小_JAVA中精确计算金额BigDecimal
  19. python练习一(对txt文本的操作:切割,切片,格式化输出)
  20. HDU 5445 (多重背包)

热门文章

  1. MyBatis学习总结[5]-动态 SQL
  2. 简单的angular表单验证指令
  3. Java学习笔记--Swing2D图形
  4. Arduino入门笔记(5):1602液晶实验(实现时钟)
  5. 获取邮箱的DNS和MX 工具类
  6. 解决Windows x64bit环境下无法使用PLSQL Developer连接到Oracle DB中的问题
  7. Windows 2003上 SaltStack/Salt 和 psutil 可能存在的问题及解决
  8. 判断对象是否是某个类的实例
  9. JAVA学习之网络编程UDP篇
  10. R语言实现基本统计分析之t检验