读书笔记-Redis设计与实现-发布订阅,事务,脚本和其他
1.发布与订阅
- 服务器状态在pubsub_channels字典保存了所有频道的订阅关系:SUBSCRIBE命令负责将客户端和被订阅的频道关联到这个字典里面,而UNSUBSCRIBE命令则负责解除客户端和被退订频道之间的关联。
- 服务器状态在pubsub_patterns链表保存了所有模式的订阅关系:PSUBSCRIBE命令负责将客户端和被订阅的模式记录到这个链表中,而PUNSUBSCRIBE命令则负责移除客户端和被退订模式在链表中的记录。
- PUBLISH命令通过访问pubsub_channels字典来向频道的所有订阅者发送消息,通过访问pubsub_patterns链表来向所有匹配频道的模式的订阅者发送消息。
- PUBSUB命令的三个子命令都是通过读取pubsub_channels字典和pubsub_patterns链表中的信息来实现的。
2.事务
- 事务提供了一种将多个命令打包,然后一次性、有序地执行的机制。
- 多个命令会被入队到事务队列中,然后按先进先出(FIFO)的顺序执行。
- 事务在执行过程中不会被中断,当事务队列中的所有命令都被执行完毕之后,事务才会结束。
- 带有WATCH命令的事务会将客户端和被监视的键在数据库的watched_keys字典中进行关联,当键被修改时,程序会将所有监视被修改键的客户端的REDIS_DIRTY_CAS标志打开。
- 只有在客户端的REDIS_DIRTY_CAS标志未被打开时,服务器才会执行客户端提交的事务,否则的话,服务器将拒绝执行客户端提交的事务。
- Redis的事务总是具有ACID中的原子性、一致性和隔离性,当服务器运行在AOF持久化模式下,并且appendfsync选项的值为always时,事务也具有耐久性。
3.Lua脚本
- Redis服务器在启动时,会对内嵌的Lua环境执行一系列修改操作,从而确保内嵌的Lua环境可以满足Redis在功能性、安全性等方面的需要。
- Redis服务器专门使用一个伪客户端来执行Lua脚本中包含的Redis命令。
- Redis使用脚本字典来保存所有被EVAL命令执行过,或者被SCRIPT LOAD命令载入过的Lua脚本,这些脚本可以用于实现SCRIPT EXISTS命令,以及实现脚本复制功能。
- EVAL命令为客户端输入的脚本在Lua环境中定义一个函数,并通过调用这个函数来执行脚本。
- EVALSHA命令通过直接调用Lua环境中已定义的函数来执行脚本。
- SCRIPT FLUSH命令会清空服务器lua_scripts字典中保存的脚本,并重置Lua环境。
- SCRIPT EXISTS命令接受一个或多个SHA1校验和为参数,并通过检查lua_scripts字典来确认校验和对应的脚本是否存在。
- SCRIPT LOAD命令接受一个Lua脚本为参数,为该脚本在Lua环境中创建函数,并将脚本保存到lua_scripts字典中。
- 服务器在执行脚本之前,会为Lua环境设置一个超时处理钩子,当脚本出现超时运行
4.排序
- SORT命令通过将被排序键包含的元素载入到数组里面,然后对数组进行排序来完成对键进行排序的工作。
- 在默认情况下,SORT命令假设被排序键包含的都是数字值,并且以数字值的方式来进行排序。
- 如果SORT命令使用了ALPHA选项,那么SORT命令假设被排序键包含的都是字符串值,并且以字符串的方式来进行排序。
- SORT命令的排序操作由快速排序算法实现。
- SORT命令会根据用户是否使用了DESC选项来决定是使用升序对比还是降序对比来比较被排序的元素,升序对比会产生升序排序结果,被排序的元素按值的大小从小到大排列,降序对比会产生降序排序结果,被排序的元素按值的大小从大到小排列。
- 当SORT命令使用了BY选项时,命令使用其他键的值作为权重来进行排序操作。
- 当SORT命令使用了LIMIT选项时,命令只保留排序结果集中LIMIT选项指定的元素。
- 当SORT命令使用了GET选项时,命令会根据排序结果集中的元素,以及GET选项给定的模式,查找并返回其他键的值,而不是返回被排序的元素。
- 当SORT命令使用了STORE选项时,命令会将排序结果集保存在指定的键里面。
- 当SORT命令同时使用多个选项时,命令先执行排序
5.二进制位数组
- Redis使用SDS来保存位数组。
- SDS使用逆序来保存位数组,这种保存顺序简化了SETBIT命令的实现,使得SETBIT命令可以在不移动现有二进制位的情况下,对位数组进行空间扩展。
- BITCOUNT命令使用了查表算法和variable-precision SWAR算法来优化命令的执行效率。
- BITOP命令的所有操作都使用C语言内置的位操作来实现。
6.慢查询日志
- Redis的慢查询日志功能用于记录执行时间超过指定时长的命令。
- slowlog get
- Redis服务器将所有的慢查询日志保存在服务器状态的slowlog链表中,每个链表节点都包含一个slowlogEntry结构,每个slowlogEntry结构代表一条慢查询日志。
- 打印和删除慢查询日志可以通过遍历slowlog链表来完成。
- slowlog链表的长度就是服务器所保存慢查询日志的数量。
- 新的慢查询日志会被添加到slowlog链表的表头,如果日志的数量超过slowlog-max-len选项的值,那么多出来的日志会被删除。
7.监视器
- 客户端可以通过执行MONITOR命令,将客户端转换成监视器,接收并打印服务器处理的每个命令请求的相关信息。
- 当一个客户端从普通客户端变为监视器时,该客户端的REDIS_MONITOR标识会被打开。
- 服务器将所有监视器都记录在monitors链表中。
- 每次处理命令请求时,服务器都会遍历monitors链表,将相关信息发送给监视器。