Redis - 扩展- Lua

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zanpengfei/article/details/85835002

如果用户想自定义扩从多个指令来完成特定领域的问题,Redis提供了Lua脚本,Redis服务器会单线程原子性执行lua脚本,保证了在执行过程中不会被其他请求打断。

1、通过Lua脚本执行多个指令

if redis.call("get",KEYS[1]) == ARGV[1] then

    return redis.call("del",KEYS[1])

else

    return 0

end

 

解析:如果通过key获取的数据与第一个入参相等,则将该key删除,并且返回,否则返回0。

将上面的脚本转换成Redis可以识别的格式,采用EVAL指令,如下

127.0.0.1:6379> set foo bar

OK

127.0.0.1:6379> eval 'if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end' 1 foo bar

(integer) 1

127.0.0.1:6379> eval 'if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end' 1 foo bar

(integer) 0

 

解析:第二次执行返回0的原因是第一次已经把它删除了。

2、SCRIPT LOAD 和 EVALSHA指令

如果lua脚本内容很长,而且客户端需要频繁操作,如果没次都需要传递那么大的脚本,必然存在浪费网络流量,所以Redis提供SCRIPT LOAD 和 EVALSHA指令

1) SCRIPT LOAD 指令用于将客户端提供的 lua 脚本传递到服务器而不执行,但是会得到脚本的唯一 ID,这个唯一 ID 是用来唯一标识服务器缓存的这段 lua 脚本,入下表:

127.0.0.1:6379> script load 'local curVal = redis.call("get", KEYS[1]); if curVal == false then curVal = 0 else curVal = tonumber(curVal) end; curVal = curVal * tonumber(ARGV[1]); redis.call("set", KEYS[1], curVal); return curVal'

 

"be4f93d8a5379e5e5b768a74e77c8a4eb0434441"

 

将得到一个ID be4f93d8a5379e5e5b768a74e77c8a4eb0434441

2)EVALSHA指令用来执行该Lua脚本,入下表

127.0.0.1:6379> evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 notexistskey 5

(integer) 0

127.0.0.1:6379> evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 notexistskey 5

(integer) 0

127.0.0.1:6379> set foo 1

OK

127.0.0.1:6379> evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 foo 5

(integer) 5

127.0.0.1:6379> evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 foo 5

(integer) 25

 

解析:前俩句由于redis中不存在 key notexistskey 值为5的情况,所有返回0

3、错误处理

1)pcall(f)函数是Redis使f函数运行在保护模式下,如果f出现错误,pcall调用返回false和错误消息

2)call(f)函数,如果f出现错误时只会向上抛出异常

4、错误传递

5、脚本死循环

Redis 为了解决这个问题,它提供了script kill 指令用于动态杀死一个执行时间超时的 lua 脚本。但 script kill 的执行有一个重要的前提,那就是当前正在执行的脚本没有对 Redis 的内部数据状态进行修改,因为 Redis 不允许 script kill 破坏脚本执行的原子性。比如脚本内部使用了 redis.call("set", key, value) 修改了内部的数据,那么 script kill 执行时服务器会返回错误。

6、Script Kill 的原理

Lua 脚本引擎功能太强大了,它提供了各种钩子函数,它允许在内部虚拟机执行指令时运行钩子代码。比如每执行 N 条指令执行一次某个钩子函数,Redis 正是使用了这个钩子函数。如下图36

          Redis在钩子函数里会去处理客户端的请求,并且只有在发现 lua 脚本执行超时之后才会去处理请求,这个超时时间默认是5秒。所以当脚本卡死后,执行kill命令,会出现执行时间比较长的现象。

猜你喜欢

转载自blog.csdn.net/zanpengfei/article/details/85835002
今日推荐