在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
核心知识点: 1.Redis中执行Lua脚本的两种方法: a.eval b.evalsha 2.Lua中对redis的访问(redis.call()) 3.管理Lua脚本 a.script load:加载 b.script exists:判断 c.script flush:清除 d.script kill:杀死(如果已经执行过写操作,必须使用shutdown nosave)重启服务
1.在Redis中使用Lua 在Redis中执行Lua脚本有两种方法:eval和evalsha。 (1)eval 语法: eval 脚本内容 key个数 key列表 参数列表 下面例子使用了key列表和参数列表来为Lua脚本提供更多的灵活性: 127.0.0.1:6379> eval 'return "hello" .. KEYS[1]..ARGV[1]' 1 redis world "helloredisworld" 此时KEYS[1]="redis",ARGV[1]="world",所以最终的返回结果是“helloredisworld”。 如果脚本较长,还可以使用redis-cli--eval直接执行文件。 eval命令和--eval参数本质是一样的,客户端如果想执行Lua脚本, 首先在客户端编写好Lua脚本代码,然后把脚本作为字符串发送给服务端,服务端会将执行结果返回给客户端。
(2)evalsha 除了使用eval,Redis还提供了evalsha命令来执行脚本。 首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和, evalsha命令使用SHA1作为参数可以直接执行对应的Lua脚本,避免每次发送Lua脚本的开销。 这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到复用。 加载脚本:script load命令可以将脚本内容加载到Redis内存中,例如: 127.0.0.1:6379> script load "return 'hello kebi'" "8df13960c2be12fec0947206c9e087cd68b2f1b9" 执行脚本:evalsha可以执行脚本: 127.0.0.1:6379> evalsha "8df13960c2be12fec0947206c9e087cd68b2f1b9" 0 "hello kebi"
2.Lua的Redis API Lua可以使用redis.call函数实现对Redis的访问: 127.0.0.1:6379> eval 'return redis.call("get",KEYS[1])' 1 hello "world" 除此之外Lua还可以使用Redis.pcall函数实现对Redis的调用,redis.call和redis.pcall的不同在于, 如果redis.call执行失败,那么脚本执行结束会直接返回错误,而redis.pcall会忽略错误继续执行脚本, 所在实际开发中要根据具体的应用场景进行函数的选择。 Lua可以使用redis.log函数将Lua脚本的日志输出到Redis的日志文件中,但是一定要控制日志级别。
3.Redis如何管理Lua脚本 Redis提供了4个命令实现对Lua脚本的管理,下面分别介绍: (1)script load script load script 将Lua脚本加载到Redis内存之中。
(2)script exists scripts exists sha1 [sha1 ...] 判断sha1是否已经加载到Redis内存之中。 127.0.0.1:6379> script load "return 'hello kebi'" "8df13960c2be12fec0947206c9e087cd68b2f1b9" 127.0.0.1:6379> script exists "8df13960c2be12fec0947206c9e087cd68b2f1b9" 1) (integer) 1
(3)script flush script flush 清除Redis内存中已经加载的所有Lua脚本。 127.0.0.1:6379> script exists "8df13960c2be12fec0947206c9e087cd68b2f1b9" 1) (integer) 1 127.0.0.1:6379> script flush OK 127.0.0.1:6379> script exists "8df13960c2be12fec0947206c9e087cd68b2f1b9" 1) (integer) 0
(4)script kill script kill 此命令用于杀掉正在执行的Lua脚本。 如果Lua脚本比较耗时,甚至Lua脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或外部进行干预将其结束。 下面模拟一个Lua脚本阻塞的情况进行说明。 执行Lua脚本,当前客户端会阻塞: 127.0.0.1:6379> eval 'while 1==1 do end' 0 ..卡在这里不动了,因为这个脚本一直做死循环 在另外一个客户端执行一个命令: 127.0.0.1:6379> get world (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. 此时Redis已经阻塞,无法处理正常的调用,可以使用script kill结束当前正在执行的Lua脚本: 127.0.0.1:6379> script kill OK 可在阻塞的那一端看到(脚本被杀死的信息): 127.0.0.1:6379> eval 'while 1==1 do end' 0 (error) ERR Error running script (call to f_c045d3ae3b3eca855e00c772db40aa560b3a1fc8): @user_script:1: Script killed by user with SCRIPT KILL... (38.91s) 注意:如果当前Lua脚本已经执行过写操作,那么script kill将不会生效。例如: 127.0.0.1:6379> eval 'while 1==1 do redis.call("set","k","v") end' 0 --一直执行写操作 在另一个客户端使用script kill杀不掉: 127.0.0.1:6379> script kill (error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command. 此时唯一的办法就是重启服务,必须使用shutdown nosave: --不能以这种方法关 [root@Redis ~]# redis-cli shutdown (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. --必须这样 127.0.0.1:6379> shutdown nosave not connected> 然后再开 补充: Redis提供了一个lua-time-limit参数,默认是5秒,它是Lua脚本的“超时时间”,但这个超时时间仅仅是当Lua脚本超过lua-time-limit后,向其他命令发送BUSY的信号,但是不会停止掉服务端和客户端的执行脚本。
4.使用Lua对Redis中的数据进行处理(案例) Lua脚本功能为Redis开发和运维人员带来如下三个好处:
下面以一个例子说明·Lua脚本的使用,当前列表记录着热门用户的id,假设这个列表有5个元素,如下所示: 127.0.0.1:6379> lrange hot:user:list 0 -1 1) "user:1:ratio" 2) "user:8:ratio" 3) "user:3:ratio" 4) "user:4:ratio" 5) "user:72:ratio" user:{id}:ratio代表用户的热度,它本身又是一个字符串类型的键: 127.0.0.1:6379> mget user:1:ratio user:8:ratio user:3:ratio user:4:ratio user:72:ratio
1) "987"
2) "763"
3) "556"
4) "400"
5) "101"
现要求将列表内所有的键对应热度做加1操作,并且保证是原子性执行,此功能可以利用Lua脚本来实现。 脚本内容如下: --将列表中所有元素取出,赋值给mylist local mylist = redis.call("lrange",KEYS[1],0,1) --定义局部变量count=0,这个count就是最后incr的总次数 local count = 0 --遍历mylist中所有元素,每次做完count自增,最后返回count for index,key in ipairs(mylist) do redis.call("incr",key) count = count + 1 end return count 执行脚本: [root@Redis script.lua]# redis-cli --eval 3_1.lua hot:user:list
(integer) 5
执行后用户热度自增1: 127.0.0.1:6379> mget user:1:ratio user:8:ratio user:3:ratio user:4:ratio user:72:ratio
1) "987"
2) "763"
3) "557"
4) "401"
5) "101"
|
请发表评论