设为首页 加入收藏

TOP

《Redis设计与实现》学习笔记-Lua脚本
2015-11-21 01:31:51 来源: 作者: 【 】 浏览:0
Tags:Redis 设计 实现 学习 笔记 -Lua 脚本
Redis从2.6开始支持Lua脚本,和事务的功能类似,可以通过Lua脚本原子的执行多个Redis命令。Redis提供了eva l和eva lSHA命令执行lua脚本。

创建并修改Lua坏境

Redis在服务器内嵌了一个Lua坏境,并进行了一系列的修改,从而确保这个Lua坏境可以满足Redis服务器的需要,通过下列步骤创建并修改Lua坏境:

创建一个基础Lua坏境,通过调用Lua的C API函数lua_open。载入多个函数库到Lua坏境中,让Lua脚本可以使用这些函数来进行数据操作。包括Lua核心函数(assert、error、pairs、tostring、pcall等)、表格库(比如table.concat、table.insert等)、字符串库(string.x)、数学库(math.x)、调试库(debug.x)、CJSON库、Struct库、cmsgpack库。创建全局表格redis,该表格包含了对Redis进行操作的函数,比如用于在Lua脚本中执行Redis命令的redis.call和redis.pcall函数、用于记录日志的redis.log函数。使用Redis自制的随机函数替换Lua原有的副作用随机函数,替换后的随机函数对于相同的seed总会产生相同的随机数序列。创建排序辅助函数,Lua坏境使用这个辅助函数来对一部分Redis命令的结果进行排序,消除命令的不确定性,比如SMEMBERS这种命令多次执行可能会产生不同的结果,通过辅助函数来对结果进行排序让它们每次产生同样的结果。创建redis.pcall函数的错误报告辅助函数,提供详细的出错信息。对Lua坏境中的全局变量进行保护,防止用户在执行Lua脚本的过程中,将额外的变量添加到Lua坏境中,不过Redis没有禁止用户修改已存在的全局变量,所以使用Lua脚本的时候需要小心,以免错误的修改了已存在的全局变量。将完成修改的Lua坏境保存到服务器状态的lua属性(redisServer结构的属性)中,等待执行服务器传来的Lua脚本。

Lua坏境协作组件

Redis服务器创建了两个用于与Lua坏境进行协作的组件,它们分别是负责执行Lua脚本中的Redis命令的伪客户端,以及用于保存Lua脚本的lua_scripts字典。

伪客户端

伪客户端负责处理Lua脚本中包含的Redis命令,Lua脚本使用redis.call或者redis.pcall函数执行一个Redis命令,需要以下步骤:
Lua坏境将redis.call或者redis.pcall函数想要执行的命令传给伪客户端。伪客户端将脚本想要执行的命令传给命令执行器。命令执行器执行伪客户端传给它的命令,并将命令的执行结果返回给客户端。伪客户端接收命令执行器返回的命令结果,并将这个命令结果返回给Lua坏境。Lua坏境在接收到命令结果之后,将该结果返回给redis.call或者redis.pcall。接收到结果的redis.call或redis.pcall函数将命令结果作为函数返回值返回给脚本的调用者。

lua_scripts字典

作为一个属性存放在redisServer结构中,字典的键为Lua脚本的SHA1校验和,而字典的值时SHA1校验和对应的Lua脚本,Redis服务器会将所有被eva l命令执行过的Lua脚本,以及所有被SCRIPT LOAD命令载入过的Lua脚本都保存到lua_scripts字典里面。

eva l命令

eva l命令实现分为三个步骤:
1、根据客户端给定的Lua脚本,在Lua坏境中定义一个Lua函数,函数名称由f_前缀加上脚本的SHA1校验和(四十个字符)组成,函数体为脚本本身。
2、将客户端给定的脚本保存到lua_scripts字典中。
3、执行步骤1中定义的函数,以此来执行客户端给定的Lua脚本,过程如下:

将eva l命令中传入的键名参数和脚本参数分别保存到KEYS数组和ARGV数组,然后将这两个数组作为全局变量传入到Lua坏境里面。为Lua坏境装载超时处理钩子,这个钩子可以在脚本出现超时运行的情况时,让客户端通过SCRIPT KILL命令停止脚本,或者通过SHUTDOWN命令直接关闭服务器。执行脚本函数。移除之前装载的超时钩子。将执行脚本函数所得的结果保存到客户端状态的输出缓冲区中,等待服务器将结果返回给客户端。对Lua坏境执行垃圾回收操作。

eva lSHA命令

每个被eva l命令成功执行过的Lua脚本都会生成一个SHA1校验和,为了节省带宽资源,在下次执行相同的脚本时可以使用eva lSHA命令,把之前生成的校验和传到服务器就可以了。

脚本管理命令

SCRIPT FLUSH,用于清除服务器中所有和Lua脚本有关的信息:释放lua_scripts字典,关闭现有的Lua坏境并重新创建一个Lua坏境。SCRIPT EXISTS,根据输入的SHA1校验和,检查对应的脚本是否存在,通过检查lua_scripts字典。SCRIPT LOAD,将脚本保存到lua_scripts字典中。SCRIPT KILL,当服务器设置了lua-time-limit配置选项,每次执行lua脚本之前,服务器都会在Lua坏境中设置一个超时钩子,超时钩子在脚本运行期间检查,一旦脚本的执行时间超过了lua-time-limit,钩子将定期在脚本运行的间隙中查看是否有SCRIPT KILL或者SHUTDOWN命令。如果超时的脚本未执行过任何写入操作,那么客户端可以通过SCRIPT KILL来指示服务器停止执行这个脚本,如果执行过写入操作,客户端只能用SHUTDOWN nosave命令停止服务器,防止不合法的数据写入 数据库

脚本复制

当服务器运行在复制模式下,eva l命令、SCRIPT FLUSH、SCRIPT LOAD、eva lSHA命令会复制给从服务器,除了eva lSHA命令,其它三个命令都是直接传播,在传播eva lSHA命令,先检查从服务器是否加载过这个命令,如果加载过了直接复制,如果未加载过先要把eva lSHA命令转换成等价的eva l命令再传播。
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇技术日记-150726 下一篇Linux下screen命令的使用

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: