lua脚本解密工具 欲求不满之 Redis Lua脚本的执行原理

11/28 06:15:00 来源网站:辅助卡盟平台

Redis 在 lua 脚本中除了提供了 redis.call 函数外,同样也提供了redis.pcall函数。前者遇到错误向上抛出异常,后者会返回错误信息。使用时一定要注意 call 函数出错时会中断脚本的执行,为了保证脚本的原子性,要谨慎使用。

错误传递

redis.call 函数调用会产生错误,脚本遇到这种错误会返回怎样的信息呢?我们再看个例子

客户端输出的依然是一个通用的错误消息,而不是 incr 调用本应该返回的 WRONGTYPE 类型的错误消息。Redis 内部在处理 redis.call 遇到错误时是向上抛出异常,外围的用户看不见的 pcall调用捕获到脚本异常时会向客户端回复通用的错误信息。如果我们将上面的 call 改成 pcall,结果就会不一样,它可以将内部指令返回的特定错误向上传递。

脚本死循环怎么办?

Redis 的指令执行是个单线程,这个单线程还要执行来自客户端的 lua 脚本。如果 lua 脚本中来一个死循环,是不是 Redis 就完蛋了?Redis 为了解决这个问题,它提供了 script kill 指令用于动态杀死一个执行时间超时的 lua 脚本。不过 script kill 的执行有一个重要的前提,那就是当前正在执行的脚本没有对 Redis 的内部数据状态进行修改,因为 Redis 不允许 script kill 破坏脚本执行的原子性。比如脚本内部使用了 redis.call("set", key, value) 修改了内部的数据,那么 script kill 执行时服务器会返回错误。下面我们来尝试以下 script kill指令。

eval指令执行后,可以明显看出来 redis 卡死了,死活没有任何响应lua脚本解密工具,如果去观察 Redis 服务器日志可以看到日志在疯狂输出 hello 字符串。这时候就必须重新开启一个 redis-cli 来执行 script kill 指令。

再回过头看 eval 指令的输出

看到这里细心的同学会注意到两个疑点,第一个是 script kill 指令为什么执行了 2.58 秒,第二个是脚本都卡死了,Redis 哪里来的闲功夫接受 script kill 指令。如果你自己尝试了在第二个窗口执行 redis-cli 去连接服务器,你还会发现第三个疑点,redis-cli 建立连接有点慢,大约顿了有 1 秒左右。

Script Kill 的原理

下面我就要开始揭秘kill的原理了,lua 脚本引擎功能太强大了,它提供了各式各样的钩子函数,它允许在内部虚拟机执行指令时运行钩子代码。比如每执行 N 条指令执行一次某个钩子函数,Redis 正是使用了这个钩子函数。

Redis 在钩子函数里会忙里偷闲去处理客户端的请求,并且只有在发现 lua 脚本执行超时之后才会去处理请求,这个超时时间默认是 5 秒。于是上面提出的三个疑点也就烟消云散了。

思考题

在延时队列小节辅助论坛,我们使用 zrangebyscore 和 zdel 两条指令来争抢延时队列中的任务,通过 zdel 的返回值来决定是哪个客户端抢到了任务,这意味着那些没有抢到任务的客户端会有这样一种感受 —— 到了嘴边的肉(任务)最后还被别人抢走了,会很不爽。如果可以使用 lua 脚本来实现争抢逻辑,将 zrangebyscore 和zdel指令原子性执行就不会存在这种问题,读者可以尝试一下

来源:【九爱网址导航www.fuzhukm.com】 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    暂无相关资讯
lua脚本解密工具 欲求不满之 Redis Lua脚本的执行原理