作用: 通过在服务器嵌入Lua环境,客户端可以使用Lua脚本,直接在服务器端原子性地执行多个Redis命令
EVAL:可以直接对输入的脚本进行求值 EVALSHA:可以根据脚本的SHA1校验和来对脚本进行求职;要求校验和对应的脚本至少被EVAL执行过一次或曾被SCRIPT LOAD 命令载入过
过程:8步 接下来逐一介绍这些步骤
调用Lua的C API函数lua_open,创建一个新的Lua环境
创建一个redis表格(table)并将其设为全局变量,其包含的函数有: 通过redis.call和redis.pcall函数,用户可以直接在Lua脚本中执行Redis命令:
原因:防止带有副作用的函数令脚本产生不一致的数据 使用自制函数替换了math库的math.random和math.randomsees,两个替换函数有以下特征:
原因:对于Lua脚本,除了20.1.4,另一个可能产生不一致数据的地方是那些带有不确定性质的命令
例子:set 在相同数据集上可能会产生不同输出的命令称为”带有不确定性的命令“,如SMEMBERS,还有: 解决: 例子:
内容:
内容: 即当脚本试图创建一个全局变量或获取一个不存在的全局变量,都会报错;不过可以修改
将Lua环境和服务器状态的lua属性关联起来: 只需要创建一个Lua环境的原因:
创建两个组件:一个是负责执行Lua脚本中的Redis命令的伪客户端,一个是用于保存Lua脚本的lua_scripts字典
作用: 使用redis.call函数或redis.pcall函数执行一个redis命令的流程如下:
键为某个Lua脚本的SHA1校验和,值为SHA1校验和对应的Lua脚本: 例子: 作用:实现SCRPIT EXISTS命令(键,20.5.2)和脚本复制功能(值,20.6.2.3)
20.3、20.4、20.5与命令实现有关,请看《Redis设计与实现》第二十章总结二:Lua脚本之命令实现
当服务器运行在复制模式之下时,具有写性质的脚本命令也会被复制到从服务器
命令为EVAL、SCRIPT FLUSH、SCRIPT LOAD、EVALSHA
与复制其他普通命令相同,直接传播给从服务器:
EVAL效果:主从服务器都会执行相同的Lua脚本
SCRIPT FLUSH效果:主从服务器都会重置自己的Lua环境,并清空自己的脚本字典
SCRIPT LOAD效果:主从服务器都会载入相同的Lua脚本
不能直接传播命令的原因: 1.可能主从服务器的lua_scripts字典不相同,主服务器能够执行的,从服务器可能执行不了,出现脚本未找到错误;出现在从服务器开始复制主服务器之前,主服务器已执行过某些脚本的场景 2.多个从服务器之间载入Lua脚本的情况也可能各有不同,一个从服务器成功,不代表其他的从服务器也能成功;出现在不同从服务器开始复制主服务器的时间不同的场景
解决:涉及lua_scripts字典和repl_scriptcache_dict字典
主服务器使用redisServer的repl_scriptcache_dict字典来记录自己已经将哪些脚本传播给了所有从服务器: 键为Lua脚本的SHA1校验和,值全为null
当EVALSHA命令的校验和在repl_scriptcache_dict字典中时,主服务器可以向从服务器传播此EVALSHA命令; 如果只存在于lua_scripts字典而不存在于repl_scriptcache_dict字典中时,那么至少会有一个从服务器遇上脚本未找到错误
通过EVALSHA指定的SHA1校验和以及lua_scripts字典保存的Lua脚本进行转换: 场景: 之后,针对此校验和,就可以直接使用EVALSHA命令了:
主服务执行EVALSHA之后,将判断此命令给定的校验和是否存在于repl_scriptcache_dict字典中,来决定传播EVAL还是EVALSHA:若存在,则传播EVALSHA;若不存在,则转换成等价的EVAL再传播,然后将此校验和添加到主服务器的repl_scriptcache_dict字典中