redis设计与实现5-Lua脚本、排序和二进制位数组

473 阅读5分钟

欢迎大家关注 github.com/hsfxuebao/j… ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

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环境设置一个超时处理的钩子,当脚本出现超时运行情况时,客户端可以铜鼓向服务器发送SCRIPT KILL 命令让钩子停止正在执行的脚本,或者发送SHUTDOWN nosave命令让钩子关闭整个服务器

  • 主服务器复制EVAL 、 SCRIPT FLUSH、SCRIPT LOAD 三个命令的方法和复制普通Redis命令一样,只要将相同的命令传播给从服务器就可以

  • 主服务器在复制EVALSHA命令中,必须确保素有从服务器都已经载入了EVALSHA命令指定的SHA1校验和对应的脚本,如果不能确保这一点,主服务器会将EVALSHA命令转成等效的EVAL命令,并通过EVAL命令来获得相同的脚本执行效果

排序

回顾

  • SORT命令通过将被排序键包含的元素载入到数组里,然后对数组进行排序
  • 默认情况下,SORT命令假设被排序键包含的都是数字值,以数字值的方式进行排序
  • SORT命令使用了ALPHA选项,那么SORT命令假设被排序键包含的都是字符串,以字符串的方式进行排序
  • SORT命令的排序操作快排算法实现
  • SORT命令会根据用户是否使用了DESC选项决定使用升序还是降序
  • SORT命令使用BY选项时,命令使用其他键的值来进行排序操作
  • SORT命令使用LIMIT选项时,命令只保留排序结果集中LIMIT选项指定的元素
  • SORT命令使用STORE选项时,会将排序结果集保存在指定的键里面
  • SORT命令同时使用多个选项时,,先执行排序操作(ALPHA、ASC、DESC、BY),然后执行LIMIT选项,之后执行GET选项,再执行STORE选项,最后将排序结果集返回给客户端
  • 除了GET选项之外,调整选项的摆放位置不会影响STORE命令的排序结果

二进制位数组

位数组的表示

使用字符串对象表示位数组,因为字符串对象使用SDS数据结构是二进制安全的

buf数组保存的顺序和我们平时书写位数组的顺序是完全相反的,上图中位数组为 0100 1101 ,

假如每次扩展buf数组之后,程序都需要将位数组已有的位进行移动,然后才执行写入操作,这比setbit命令实现方式更复杂,而且移位带来的CPU时间消耗也会影响命令的执行速度,所以采用setbit命令采用倒序的方式完成扩展,写入操作可以直接在扩展的二进制未中完成,而不必改动数组原来已有的二进制位

bitcount命令实现

三种常用的算法:

  • 遍历算法

  • 查表算法,保存一张表,表的键为某种排列的位数组,值为该位数组中1的个数

  • 二进制位统计算法:variable-precision SWAR算法:计算汉明重量

Redis中采用的算法:

采用了查表和cariable-precision SWAR两种算法,未处理的二进制位数大于等于128位,采用SWAR算法,否则采用查表算法;实现的算法负责度为O(n),n为输入二进制的数量

重点回顾

  • Redis使用SDS保存二进制数组
  • SDS使用逆序保存位数组,这种保存顺序简化了SETBIT命令的实现,使得setbit命令可以在不移动现有二进制位的情况下,对位数组进行空间扩展
  • BITCOUNT命令使用了查表和variable-precision SWAR算法优化命令的执行效率
  • BITOP命令的所有操作都使用C语言内置的位操作来实现

慢日志查询

回顾

  • Redis慢日志查询功能用于记录执行时间超过指定时长的命令
  • Redis服务器将所有的慢查询日志保存在服务器状态的slowlog链表中,每个链表节点都包含一个slowlogEntry结构,每个slowlogEntry结构表示一条慢查询日志
  • 打印和删除慢查询日志可以通过遍历slowlog链表完成
  • slowlog链表的长度就是服务器保存的慢查询日志的数量
  • 新的慢查询日志会被添加到slowlog链表的表头,如果日志的数量超过slowlog-max-len选项的值,多出来的日志将会删除

监视器

回顾

  • 客户端可以通过执行MONITOR命令,将客户端转换成监视器,接收并打印服务器处理的每个命令请求的相关信息
  • 当一个客户端从普通客户端变成监视器,这个客户端REDIS_MONITOR标识会被打开
  • 服务器将所有的监视器记录在monitors链表中
  • 每次处理命令请求中,服务器都会遍历monitors链表,将相关信息发送给监视器