Redis中的Lua脚本(四)

Lua脚本

脚本管理命令的实现

Redis中与Lua脚本有关的命令还有四个,它们分别是SCRIPT FLUSH命令、SCRIPT EXISTS命令、SCRIPT LOAD命令、以及SCRIPT KILL命令

SCRIPT FLUSH

SCRIPT FLUSH命令用于清除服务器中所有和Lua脚本有关的信息,这个命令会释放并重建lua_scripts字典,关闭现有的Lua环境并重新创建一个新的Lua环境。以下为SCRIPT FLUSH命令的实现伪代码:

def SCRIPT_FLUSH():
# 释放脚本字典
dictRelease(server.lua_scripts)

# 重建脚本字典
server.lua_scripts = dictCreate(...)

# 关闭Lua环境
lua_close(server.lua)

# 初始化一个新的Lua环境
server.lua = init_lua_env()

SCRIPT EXISTS

SCRIPT EXISTS命令根据输入的SHA1校验和,检查校验和对应的脚本是否存在于服务器中.SCRIPT EXISTS命令是通过检查给定的校验和是否存在于lua_scripts字典来实现的,以下是该命令的实现伪代码:

def SCRIPT_EXISTS(*sha1_list):
# 结果列表
result_list = []
# 遍历输入的所有SHA1校验和
for sha1 in sha1_list:
# 检查校验和是否为lua_scripts字典的键
# 如果是的话,那么表示校验和对应的脚本存在
# 否则的话,脚本就不存在
if sha1 in server.lua_scripts:
# 存在用1表示
result_list.append(1)
else:
# 不存在用0表示
result_list.append(0)

# 向客户端返回结果列表
send_list_reply(result_list)
例子
  • 举个例子。对于如图所示的lua_scripts字典来说,可以进行测试:
127.0.0.1:6379> SCRIPT EXISTS "2f31ba2bb6d6a0f42cc159d2e2dad55440778de3"
1) (integer) 1
127.0.0.1:6379> SCRIPT EXISTS "a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9"
1) (integer) 1
127.0.0.1:6379> SCRIPT EXISTS "4475bfb5919b5ad16424cb50f74d4724ae833e72"
1) (integer) 1
127.0.0.1:6379> SCRIPT EXISTS "NotExistsScriptSha1HereABCDEFGHIJKLMNOPQ"
1) (integer) 0

从测试结果可知,除了最后一个校验和之外,其他校验和对应的脚本都存在于服务器中
在这里插入图片描述

注意
  • 注意。
    SCRIPT EXISTS命令允许一次传入多个SHA1校验和,不过因为SHA1校验和太长,所以分开多次进行测试。实现SCRIPT EXISTS实际上并不需要lua_scripts字典的值。如果lua_scripts字典只用于实现SCRIPT EXISTS
    命令的话,那么字典只需要保存Lua脚本的SHA1校验和就可以了,并不需要保存Lua脚本本身。lua_scripts字典既可以保存脚本的SHA1校验和,又保存脚本本身的原因是因为实现脚本复制功能

SCRIPT LOAD

SCRIPT LOAD命令所做的事情和EVAL命令执行脚本时所做的前两步完全一样,命令首先在Lua环境中为脚本创建相对应的函数,然后再将脚本保存到lua_scripts字典里面.

例子

在这里插入图片描述

  • 举个例子。如果执行以下命令
127.0.0.1:6379> SCRIPT LOAD "return 'hi'"
"2f31ba2bb6d6a0f42cc159d2e2dad55440778de3"

那么服务器将在Lua环境中创建以下函数:

function f_2f31ba2bb6d6a0f42cc159d2e2dad55440778de3()
return 'hi'
end

并将键为"2f31ba2bb6d6a0f42cc159d2e2dad55440778de3",值为"return ‘hi’"的键值对添加到服务器的lua_scripts字典里面,如图所示.
完成上述步骤之后,客户端就可以使用EVALSHA命令来执行前面被SCRIPT LOAD命令载入的脚本了

127.0.0.1:6379> EVALSHA "2f31ba2bb6d6a0f42cc159d2e2dad55440778de3" 0
"hi"

SCRIPT KILL

如果服务器设置了lua-time-limit配置选项,那么在每次执行Lua脚本之前,服务器都会在Lua环境里面设置一个超时处理钩子(hook).超时处理钩子在脚本运行期间,会定期检查脚本已经运行了多长时间,一旦钩子发现脚本的运行时间已经超过了lua-time-limit选项设置的时长,钩子将定期在脚本运行的间隙中,查看是否有SCRIPT KILL命令或者SHUTDOWN命令到达服务器。如图展示了带有超时处理钩子的脚本的运行过程。如果超时运行的脚本未执行任何写入操作,那么客户端可以通过SCRIPT KILL命令来指示服务器停止执行这个脚本,并向执行该脚本的客户端发送一个错误回复。处理完SCRIPT KILL命令之后,服务器可以继续运行。
另一方面,如果脚本已经执行过写入操作,那么客户端只能用SHUTDOWN nosave命令来停止服务器,从而防止不合法的数据被写入数据库中。
在这里插入图片描述

脚本复制

与其他普通Redis命令一样,当服务器运行在复制模式之下时,具有写性质的脚本命令也会被复制到服务器,这些命令包括EVAL命令、EVALSHA命令、SCRIPT FLUSH命令,以及SCRIPT LOAD命令

复制EVAL命令、SCRIPT FLUSH命令和SCRIPT LOAD命令

Redis复制EVAL、SCRIPT FLUSH、SCRIPT LOAD三个命令的方法和复制其他普通的Redis命令的方法一样,当主服务器执行完以上三个命令的其中一个时,主服务器会直接将被执行的命令传播(propagate)给所有从服务器,如图所示。
在这里插入图片描述

EVAL

对于EVAL命令来说,在主服务器执行的Lua脚本同样会在所有从服务器中执行。
举个例子。如果客户端向主服务器执行以下命令

127.0.0.1:6379> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 "msg" "hello world"
OK

那么主服务器在执行这个EVAL命令之后,将向所有从服务器传播这条EVAL命令,从服务器会接收并执行这条EVAL命令,最终结果是,主从服务器双方都会将数据库"msg"键的值设置为"hello world",并且将脚本:

"return redis.call('SET', KEYS[1], ARGV[1])" 1 "msg" "hello world"

保存在脚本字典里面

SCRIPT FLUSH

如果客户端向主服务器发送SCRIPT FLUSH命令,那么主服务器也会向所有从服务器传播SCRIPT FLUSH命令

SCRIPT LOAD

如果客户端使用SCRIPT LOAD命令,向主服务器载入一个Lua脚本,那么主服务器将向所有从服务器传播相同的SCRIPT LOAD命令,使得所有从服务器也会载入相同的Lua脚本。
举个例子。如果客户端向主服务器发送命令:

127.0.0.1:6379> SCRIPT LOAD "return 'hello world'"
"5332031c6b470dc5a0dd9b4bf2030dea6d65de91"

那么主服务器也会向所有从服务器传播同样的命令:

SCRIPT LOAD "return 'hello world'"

最终的结果是,主从服务器双方都会载入脚本:

"return 'hello world'"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coffee_babe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值