使用Lua脚本的好处:
- 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延
- 原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。
- 复用。客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑。
调用Lua脚本的语法:
$ redis-cli --eval path/to/redis.lua KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...
- –eval,告诉redis-cli读取并运行后面的lua脚本
- path/to/redis.lua,是lua脚本的位置
- KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
- ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
Tips 01:KEYS和ARGV中间的 ‘,’ 两边的空格,不能省略。
redis支持大部分Lua标准库
库名 | 说明 |
---|---|
Base | 提供一些基础函数 |
String | 提供用于字符串操作的函数 |
Table | 提供用于表操作的函数 |
Math | 提供数学计算函数 |
Debug | 提供用于调试的函数 |
在脚本中调用redis命令,在脚本中可以使用redis.call函数调用Redis命令
redis.call('set', 'foo', 'bar') local value=redis.call('get', 'foo') --value的值为bar
Tips 02:redis.call函数的返回值就是Redis命令的执行结果
Redis命令的返回值有5种类型,redis.call函数会将这5种类型的回复转换成对应的Lua的数据类型,具体的对应规则如下:
redis返回值类型和Lua数据类型转换规则
redis返回值类型 | Lua数据类型 |
---|---|
空 | false |
整数回复 | 数字类型 |
字符串回复 | 字符串类型 |
多行字符串回复 | table类型(数组形式) |
状态回复 | table类型(只有一个ok字段存储状态信息) |
错误回复 | table类型(只有一个err字段存储错误信息) |
redis还提供了redis.pcall函数,功能与redis.call相同,唯一的区别是:当命令执行出错时,redis.pcall会记录错误并继续执行,而redis.call会直接返回错误,不会继续执行。
在脚本中可以使用return语句将值返回给客户端,如果没有执行return语句则默认返回nil
Lua数据类型和redis返回值类型转换规则
Lua数据类型 | redis返回值类型 |
---|---|
数字类型 | 整数回复(Lua的数字类型会被自动转换成整数) |
字符串类型 | 字符串回复 |
table类型(数组形式) | 多行字符串回复 |
table类型(只有一个ok字段存储状态信息) | 状态回复 |
table类型(只有一个err字段存储错误信息) | t错误回复 |
脚本相关命令
- EVAL “lua-script” [key …] [arg …]
通过key和arg这两类参数向脚本传递数据,它们的值在脚本中分别使用KEYS和ARGV两个表类型的全局变量访问。
Tips 03: EVAL命令依据参数key-number来将其后面的所有参数分别存入脚本中KEYS和ARGV两个table类型的全局变量。当脚本不需要任何参数时,也不能省略这个参数(设为0)
redis>EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar OK redis>GET foo "bar"
- EVALSHA命令
在脚本比较长的情况下,如果每次调用脚本都需要将整个脚本传给Redis会占用较多的带宽。为了解决这个问题,Redis提供了EVALSHA命令,允许开发者通过脚本内容的SHA1摘要来执行脚本,该命令的用法和EVAL一样,只不过是将脚本内容替换成脚本内容的SHA1摘要。
Redis在执行EVAL命令时会计算脚本的SHA1摘要并记录在脚本缓存中,执行EVALSHA命令时Redis会根据提供的摘要从脚本缓存中查找对应的脚本内容,如果找到了则执行脚本,否则会返回错误:”NOSCRIPT No matching script. Please use EVAL.”
在程序中使用EVALSHA命令的一般流程如下。
- 先计算脚本的SHA1摘要,并使用EVALSHA命令执行脚本。
- 获得返回值,如果返回“NOSCRIPT”错误则使用EVAL命令重新执行脚本。
虽然这一流程略显麻烦,但值得庆幸的是很多编程语言的Redis客户端都会代替开发者完成这一流程。执行EVAL命令时,先尝试执行EVALSHA命令,如果失败了才会执行EVAL命令。
- SCRIPTLOAD “lua-script”
将脚本加入缓存,但不执行. 返回:脚本的SHA1摘要
- SCRIPT EXISTS lua-script-sha1
判断脚本是否已被缓存
- SCRIPT FLUSH
清空脚本缓存 redis将脚本的SHA1摘要加入到脚本缓存后会永久保留,不会删除,但可以手动使用SCRIPT FLUSH命令情况脚本缓存。
- SCRIPT KILL
强制终止当前脚本的执行。 但是,如果当前执行的脚步对redis的数据进行了写操作,则SCRIPT KILL命令不会终止脚本的运行,以防止脚本只执行了一部分。脚本中的所有命令,要么都执行,要么都不执行。