Redis10-lua脚本

269 阅读4分钟

Redis和Lua脚本

一、介绍:

为了保证多条命令组合的原子性,Redis提供了Lua脚本来解决和这个问题。

事务表示:一组命令,要么全部都执行成功,要么全部都执行不成功。

Lua语言包括布尔(booleans)、数值(numbers)、表格(tables)、字符串(strings)

二、在Redis中使用Lua脚本

(1)eval

描述:

redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...] 
    
script: 参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。
numkeys: 用于指定键名参数的个数。
key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。

命令:

127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"

过程:

(2)evalsha

描述:

evalsha命令使用SHA1作为参数可以直接执行对应Lua脚本,避免每次发送 Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻 在服务端,脚本功能得到了复用。

过程

命令

redis 127.0.0.1:6379> EVALSHA sha1 numkeys key [key ...] arg [arg ...] 

sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
numkeys: 用于指定键名参数的个数。
key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
127.0.0.1:6379> script load "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
127.0.0.1:6379> evalsha "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
"hello moto"
(3)Lua的redis的api
redis.call("set", "hello", "world")
redis.call("get", "hello")

redis中

127.0.0.1:6379> eval 'return redis.call("get",KEYS[1])' 1 hello "world"

redis.call和redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返 回错误,而redis.pcall会忽略错误继续执行脚本。

(4)总结

①Lua脚本在Redis中是原子性的,执行过程中不会被其它命令打断。

②Lua脚本可以帮助开发制定自己的命令,可以放在redis内存中,实现复用。

③Lua脚本可以将命令一次性打包,有效减少网络开销。

三、Redis如何管理Lua脚本

(1)script load

将Lua脚本加载到内存中。

127.0.0.1:6379> script load "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
(2)script exists

判断sha1是否加载到内存中

127.0.0.1:6379> script load "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
127.0.0.1:6379> script exists "232fd51614574cf0867b83d384a5e898cfd24e5a"
1) (integer) 1
(3)script flush

用来清除所有正在加载的Lua脚本。

127.0.0.1:6379> script exists  "232fd51614574cf0867b83d384a5e898cfd24e5a"
1) (integer) 1
127.0.0.1:6379> script flush
OK
127.0.0.1:6379> script exists "232fd51614574cf0867b83d384a5e898cfd24e5a"
1) (integer) 0

(4)script kill

用来杀死正在执行的Lua脚本。

场景:模拟一个阻塞的lua脚本

①下面的代码会使Lua进入死循环

127.0.0.1:6379> eval 'while 1==1 do end' 0

②其他客户端在执行正常的命令时,将会收到“Busy Redis is busy running a script”错误,并且提示使用script kill或者shutdown nosave命令来杀掉这个busy的脚本:

127.0.0.1:6379> get hello
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

③使用script kil来杀掉这个busy的脚本。

127.0.0.1:6379> script kill
OK
127.0.0.1:6379> get hello
"\xc4\xe3\xba\xc3"
127.0.0.1:6379>