欢迎您光临001卡盟,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

辅助lua]标签的文章】" target="_blank">绝地求生辅助lua 概览

Lua 是一个简洁、轻量、可扩展的脚本语言,它有着相对简单的API 因此很容易嵌入应用中,很多应用程序使用Lua作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。

Redis 从 2.6 版本开始支持 Lua 脚本,客户端通过 Lua 脚本,可以将多个 Redis 命令组合成一个原子性操作在服务器上执行。

例如使用 Redis 实现分布式锁时,为了保证操作原子性,通常也会使用 Lua 脚本封装锁相关的操作,以下为 Redisson 的加锁脚本实现:

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

Lua 脚本有以下优点:

•保证操作原子性

•减少网络开销,将多个指令组合到一个脚本中,与服务器的交互从多次变为一次

•可重复使用,在初次载入脚本之后,服务器会为脚本生成缓存,后续执行脚本时可直接使用缓存

基础命令

EVAL 命令:执行指定脚本;

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

SCRIPT LOAD 命令:加载指定脚本,执行成功后会返回脚本的SHA1校验和;

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

script EXISTS 命令:检查脚本是否存在于服务器,1 表示存在;0 表示不存在;

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

EVALSHA 命令:指定SHA1校验和,执行对应脚本,这种方式在脚本体量较大时,能很大程度节省网络带宽

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事实现原理

redis 的 lua 功能的实现包含以下几个核心点:

•lua 环境初始化

•lua 脚本执行

•lua 脚本管理

•lua 脚本复制

下图展示了 lua 环境的初始化,以及 lua 环境与 redis 命令执行器的交互过程。

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事lua 环境初始化

lua 环境的构建主要包含三部分:基础函数库加载,redis表格加载,定制化函数加载。

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

基础函数库加载:加载基础函数库,例如字符串库,数学库等,支持 lua 脚本中的一些复杂操作。

redis表格加载:redis表格中包含 redis.call,redis.pcall 等函数,支持 lua 脚本中进行 redis 指令调用。

定制化函数加载:

•自定义随机函数,为了保证相同脚本在不同机器上执行能产生相同的结果,而原始的math.random,math.randomseed函数均不满足要求,故 redis 自定义实现了这两个随机函数

•排序辅助函数,另一个可能产生不一致数据的地方是那些带有不确定性的指令。例如集合中元素是无序排列的,即使两个集合中元素完全相同,最终输出结果的顺序也可能不一致,因此针对那些带有不确定性的指令,redis 会通过排序辅助函数对结果进行排序

•错误报告辅助函数,用于打印脚本执行过程中的错误信息,方便调试

脚本执行

脚本执行的过程主要包含以下三个步骤:

•加载脚本,生成对应的SHA1校验和,并生成脚本缓存

•在 lua 环境中生成脚本函数

•执行脚本函数

例如执行如下脚本:

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

1.首先会生成该脚本的 SHA1校验和:e17faafbc130014cebb229b71e0148b1f8f52389

2.生成对应的脚本函数,函数命名为 f_SHA1 的形式:f_e17faafbc130014cebb229b71e0148b1f8f52389

后续直接可以直接通过SHA1校验和定位并执行对应的脚本:

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

另外如果脚本中存在 redis 指令调用,lua 环境会通过一个伪客户端与命令执行器进行交互。

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事脚本管理

除了脚本执行以外,redis 还提供了几个脚本管理的指令:

•SCRIPT FLUSH,用于清除服务器中所有和Lua脚本有关的信息

SCRIPT EXISTS,根据输入的SHA1校验和,检查校验和对应的脚本是否存在于服务器中

•SCRIPT LOAD,手动载入脚本,生成对应的SHA1校验和

•SCRIPT KILL,停止脚本执行

SCRIPT KILL 指令的实现相对更复杂一些,流程如下:

•脚本运行时间超出预先设置的 lua-time-limit 时,才允许被 SCRIPT KILL 强行停止脚本

•如果脚本中已经执行过写入操作,则不允许使用 SCRIPT KILL,只能通过 SHUTDOWN nosave 强行停止脚本,从而预防脏数据的写入

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事脚本复制

脚本复制是指当 Redis 运行在主从模式下时,主机执行了 Lua 脚本命令后,需要把命令及时同步到从机。

主要涉及上面提到的 EVAL,EVALSHA,SCRIPT FLUSH,SCRIPT LOAD 命令。

EVAL,SCRIPT FLUSH,SCRIPT LOAD 这三个命令的复制过程不复杂,与复制普通 Redis 命令的方法一样,当主机执行完这三个命令之后,直接将命令扩散给从机,从机重新执行一遍命令即可。

重点需要关注的是 EVALSHA 命令的复制,因为同样是执行 EVALSHA 命令,在从机上可能出现脚本未找到的错误,如下图所示:

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

当主机执行完 EVALSHA 0xxx1 命令后,将该命令复制到从机,但从机因为之前没有加载过 0xxx1 对应的脚本,因此执行失败了。

Redis 如何解决 EVALSHA 命令的复制问题呢?

首先 Redis 中维护了两个脚本相关的字典表:

•lua_scripts,维护当前机器已加载的脚本,键保存的是脚本的SHA1校验和,值指向脚本本身

•repl_scriptcache_dict,维护当前机器已同步给从机的脚本,键是脚本的SHA1校验和,值为空

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

复制过程如下:

•在复制 EVALSHA 命令前,会先检查脚本是否已同步至所有从机,通过 repl_scriptcache_dict 字典查询同步记录

•如果脚本已同步完成,直接复制 EVALSHA 命令,没有问题

•如果脚本未同步完成,则将 EVALSHA 命令转换成 EVAL 命令,重新触发一次从机的脚本同步

绝地求生辅助lua 关于Redis-Lua脚本,你不知道的这些事

另外值得注意的是当有新的从机上线,主机会将 repl_scriptcache_dict 字典清空,为的是重新触发对所有从机的脚本同步。