redis 排序_Redis Lua脚本、排序功能、二进制位数组、慢查询日志、监视器

本文深入探讨了Redis中Lua脚本的实现原理,包括EVAL、EVALSHA命令以及脚本管理。同时,详细介绍了SORT命令的排序机制,特别是对数字和字符串值的排序。此外,还阐述了位数组相关命令如SETBIT、GETBIT、BITCOUNT和BITOP的实现细节。最后,讨论了Redis的慢查询日志功能,包括其工作方式和如何使用SLOWLOG命令。
摘要由CSDN通过智能技术生成

一、Lua脚本:Eval、Evalsha、ScriptiLoad等命令的实现原理

1.1 创建并修改Lua环境

  • 创建Lua环境
  • 载入函数库
  • 创建redis全局表格
  • 使用Rdis自制的随机函数来替换Lua原有的随机函数
  • 创建排序辅助函数
  • 创建redis.pcall函数的错误报告辅助函数
  • 保护Lua的全局环境
  • 将Lua环境保存到服务器状态的lua属性里面

1.2 Lua环境协作组件

  • 伪客户端:用于执行Lua脚本
  • lua_scripts字典:用于保存Lua脚本。Redis服务器会将所有被EVAL命令执行过的Lua脚本,以及所有被SCRIPT LOAD命令载入过的Lua脚本都保存到lua_scripts字典里面。用于实现SCRIPT EXISTS命令以及脚本复制功能

1.3 EVAL命令的实现

  • 定义脚本函数
当客户端向服务器发送 EVAL命令,要求海之星Lua脚本时,会首先要在Lua环境中,为传入的脚本定义一个与这个脚本相对应的Lua函数,函数名字由f_前缀加上脚本的SHAI校验和组成,而函数体则是脚本本身
  • 将脚本保存到lua_script字典
  • 执行脚本函数

1.4 EVALSHA命令的实现

每个被 EVAL命令成功执行过的Lua脚本,在Lua环境里面都有一个与这个脚本相对应的函数,函数名由f_前缀加校验和组成。客户端可以根据这个校验和来调用脚本对应的函数,从而到达执行脚本目的。

1.5 脚本管理命令的实现

  • SCRIPT FLUSH
清除服务器中所有和Lua脚本有关的信息,并释放重建 lua_scripts字典,关闭现有的Lua环境并重新创建一个新的Lua环境
  • SCRIPT EXISTS
根据输入的SHA1校验和,检查校验和对应的脚本是否存在于服务器中,不存在返回0,存在返回1
  • SCRIPT LOAD
所做的事情和EVAL命令执行脚本时所做的前两步一样,最终会生成校验和
  • SCRIPT KILL

2a778874c153322a416eaf12a21eed49.png

1.6 脚本复制

当服务器运行在复制模式下时,具有写性质的脚本命令会被复制到从服务器
  • 复制EVAL、SCRIPT FLUSH和SCRIPT LOAD命令
  • 复制EVALSHA命令

3b49566071aa200627c9cf526427756b.png

重点回顾:

(1)Rdis服务器在启动时会对内嵌的lua环境执行一系列修改操作,从而确保内嵌环境可以满足Redis在功能性、安全性等方面需求
(2)Redis服务器专门使用一个伪客户端来执行lua脚本中包含的Redis命令
(3)Redis使用脚本字典来保存所有被EVAL命令执行过或者被SCRIPT LOAD命令载入过的lua脚本,这些脚本可以用于实现SCRIPT EXISTS命令以及实现脚本复制功能
(4)EVAL命令为客户端输入的脚本在Lua环境中定义一个函数,并通过调用这个函数来执行脚本
(5)EVALSHA命令通过直接调用Lua环境中已经定义的函数来执行脚本
(6)SCRIPT FLUSH命令会清空服务器lua_scripts字典中保存的脚本,并重置Lua环境(7)SCRIPT EXISTS命令接受一个或多个SHA1校验和为参数,并通过检查lua_scripts字典来确认校验和对应的脚本是否存在
(8)SCRIPT LOAD命令接受一个lua脚本参数,为该脚本在lua环境中创建函数,并将脚本保存到lua_scripts字典中
(9)服务器在执行脚本之前,会为Lua环境设置一个超时处理钩子,当脚本出现超时运行情况时,客户端可以通过向服务器发送SCRIPT KILL命令来让钩子停止正在执行的脚本,或者发送SHUTDOWN nosave命令让钩子关闭整个服务器
(10)主服务器复制EVAL、SCRIPT FLUSH、SCRIPT LOAD三个命令的方法和复制普通Redis命令一样,只要将相同的命令传播给从服务器就可以了
(11)主服务器在复制EVALSHA命令时,必须确保所有从服务器都已经载入了EVALSH命令指定的SHA1校验和所对应的lua脚本,如果不能确保这一点的话,主服务器会将EVALSHA命令转换成等效的EVAL命令,并通过传播EVAL命令来获取相同的脚本执行效果。

二、排序:Sort命令的实现原理 (快排)

2.1 SORT &ltkey>命令的实现

对一个包含数字值的键key进行排序。 SORT命令为每个被排序的键都创建一个与键长度相同的数组,数组的每个项都是一个 redisSortObject结构。

2.2 ALPHA选项的实现

通过使用 ALPHA选项 SORT命令可以包含字符串值的键进行排序

2.3 ASC选项和DESC选项的实现

默认是升序

2.4 BY选项的实现

2.5 带有ALPHA选项的BY选项的实现

BY选项默认假设权重键保存的值为数字值,如果权重键保存的是字符串值的话,就需要在使用BY选项的同事,配合使用ALPHA选项

2.6 LIMIT选项的实现

limit用于只返回部分已排序的元素

2.7 GET选项的实现

让SORT命令在对键进行排序之后,根据被排序的元素以及GET选项所指定的模式,查找并返回某些键的值

2.8 STORE选项的实现结果

默认情况下SORT命令只向客户端返回排序结果,而不保存排序

2.9 执行顺序

先执行排序操作(可用的选项ALPHA、ASC、DESC、BY),然后执行LIMIT选项,之后执行GET选项,再之后执行STORE选项,最后才将排序结果集返回给客户端。并且调整选项的摆放位置不会影响STORE命令的排序结果。

三、二进制位数组:GetBit、SetBit、BitCount、BitOp等命令的实现原理

Redis提供了
(1) SETBIT:为位数组指定偏移量上的二进制位设置值
(2) GETBIT:获取维数组指定偏移量上的二进制位的值
(3) BITCOUNT:统计位数组里面值为1的二进制的数量
(4) BITOP:多个位数组进行按位与、按位或、按位异或、取反等操作;四个命令处理二进制位数组

3.1 位数组的表示

Redis使用字符串对象来表示位数组,并且使用逆序来保存数组。

5cf3fb1bded88e1b615136228e2183dd.png

3.2 GETBIT命令的实现

getbit <bitarray> <offset>
  • 计算byte=|offset/8|,byte记录了offset偏移量指定的二进制位保存在位数组的哪个字节
  • 计算bit=(offset%8) + 1,bit记录了offset偏移量指定的二进制位是byte字节的第几个二进制位
  • 根据byte值和bit值在位数组bitarray中定位offset偏移量指定的二进制位,并返回这个位的值

3.3 SETBIT命令的实现

setbit <bitarray> <offset> <value>
  • 计算len=|offset/8|+1,len值记录了保存offset偏移量指定的二进制位至少需要多少字节
  • 检查bitarray键保存的位数组的长度是否小于len,是的话将SDS长度扩展为len字节,并将所有新扩展空间的二进制位的值设置为0
  • 计算byte=|offset/8|,byte记录了offset偏移量指定的二进制位保存在位数组的哪个字节
  • 计算bit=(offset mod 8) + 1,bit值记录了offset偏移量指定的二进制位是byte字节的第几个二进制位
  • 根据byte值和bit值,在bitarray键保存的位数组中定位offset偏移量指定的二进制位,首先将指定二进制位现在值保存在oldvalue变量,然后将新值value设置为这个二进制位的值
  • 向客户端返回oldvaluse变量的值

3.4 BITCOUNT命令的实现(用到了查表和variable-precisionSWAR两种算法,算法复杂度为O(n),n为输入二进制位的数量)

3.5 BITOP命令的实现

直接使用c语言内置的位操作&、|、^、~ 等操作

重点:

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

四、慢查询日志:Slow Log get、Slow Log len、Slow Log Reset等命令的实现原理

Redis的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个个功能产生的日志来监视和优化查询速度 slowlog-log-slower-than:指定执行时间超过多少微秒的命令请求会被记录到日志上 slowlog-max-len:指定服务器最多保存多少条慢查询
  • 使用SLOWLOG GET命令可以查看服务器所保存的慢查询日志
  • Redis服务将所有慢查询日志保存在服务器状态的slowlog链表中,每个链表节点都包含一个slowlogEntry结构,每个slowlogEntry结构代表一条慢查询日志
  • 打印和删除慢查询日志可以通过遍历slowlog链表来完成
  • slowlog链表长度就是服务器所保存慢查询日志的数量
  • 新的慢查询日志会被添加到slowlog链表的表头,如果日志的数量超过slowlog-max-len选项的值,那么多出来的日志会被删除

五、监视器:Monitor

通过执行 MONITOR命令,客户端可以将自己变成一个监视器,实时地接收并打印出服务器当前处理的命令请求的相关信息

885cb8c6d199444ddb4d278594bd9bd9.png
图5.1 监视器
  • 当一个客户端从普通客户端变为监视器时,该客户端的REDIS_MONITOR标识会被打开
  • 服务器将所有监视器都记录在MONITORS链表中
  • 每次处理请求命令时,服务器都会遍历monitor链表,将相关信息发送给监视器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值