简介
Redis 从2.6.0开始支持lua脚本
时间复杂度: 取决于脚本的复杂度
特点
- 减少网络开销
- 可以将多个请求通过脚本的形式一次发送,减少网络传传输时间
- 原子操作
- redis会将整个脚本作为一个整体执行,中间不会被其他命令插入, 不用担心并发操作带来的影响
- 复用
- 客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑
应用场景
需要原子执行多个命令,并且中间有逻辑判断的业务
比如秒杀扣库存
命令说明
EVAL
EVAL script numkeys key [key …] arg [arg …]
时间复杂度: 可以在 O(1) 复杂度内找到要被执行的脚本,其余的复杂度取决于执行的脚本本身
功能说明
从 Redis 2.6.0 版本开始,通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行求值。
script 参数是一段 Lua 5.1 脚本程序,它会被运行在 Redis 服务器上下文中,这段脚本不必(也不应该)定义为一个 Lua 函数。
numkeys 参数用于指定键名参数的个数。
键名参数 key [key ...] 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
在命令的最后,那些不是键名参数的附加参数 arg [arg ...] ,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
示例
> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
EVALSHA
EVALSHA sha1 numkeys key [key …] arg [arg …]
时间复杂度: 根据脚本的复杂度而定
功能说明
根据给定的 sha1 校验码,对缓存在服务器中的脚本进行求值。
将脚本缓存到服务器的操作可以通过 SCRIPT LOAD script 命令进行。
这个命令的其他地方,比如参数的传入方式,都和 EVAL script numkeys key [key …] arg [arg …] 命令一样。
示例
redis> SCRIPT LOAD "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
"hello moto"
SCRIPT
SCRIPT LOAD script
时间复杂度: O(N) , N 为脚本的长度(以字节为单位)
功能说明
将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
EVAL script numkeys key [key …] arg [arg …] 命令也会将脚本添加到脚本缓存中,但是它会立即对输入的脚本进行求值。
如果给定的脚本已经在缓存里面了,那么不做动作。
在脚本被加入到缓存之后,通过 EVALSHA 命令,可以使用脚本的 SHA1 校验和来调用这个脚本。
脚本可以在缓存中保留无限长的时间,直到执行 SCRIPT FLUSH 为止。
关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 EVAL script numkeys key [key …] arg [arg …] 命令。
返回值
给定 script 的 SHA1 校验和
示例
redis> SCRIPT LOAD "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0
"hello moto"
SCRIPT
SCRIPT EXISTS sha1 [sha1 …]
时间复杂度: O(N) , N 为给定的 SHA1 校验和的数量
功能说明
给定一个或多个脚本的 SHA1 校验和,返回一个包含 0 和 1 的列表,表示校验和所指定的脚本是否已经被保存在缓存当中。
关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 EVAL script numkeys key [key …] arg [arg …] 命令。
返回值
一个列表,包含 0 和 1 ,前者表示脚本不存在于缓存,后者表示脚本已经在缓存里面了。 列表中的元素和给定的 SHA1 校验和保持对应关系,比如列表的第三个元素的值就表示第三个 SHA1 校验和所指定的脚本在缓存中的状态
示例
redis> SCRIPT LOAD "return 'hello moto'" # 载入一个脚本
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1) (integer) 1
redis> SCRIPT FLUSH # 清空缓存
OK
redis> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1) (integer) 0
SCRIPT FLUSH
时间复杂度: O(N) , N 为缓存中脚本的数量
功能说明
清除所有 Lua 脚本缓存。
关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 EVAL script numkeys key [key …] arg [arg …] 命令
返回值
总是返回 OK
示例
redis> SCRIPT FLUSH
OK
SCRIPT KILL
时间复杂度: O(1)
功能说明
杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效。
这个命令主要用于终止运行时间过长的脚本,比如一个因为 BUG 而发生无限 loop 的脚本,诸如此类。
SCRIPT KILL 执行之后,当前正在运行的脚本会被杀死,执行这个脚本的客户端会从 EVAL script numkeys key [key …] arg [arg …] 命令的阻塞当中退出,并收到一个错误作为返回值。
另一方面,假如当前正在运行的脚本已经执行过写操作,那么即使执行 SCRIPT KILL ,也无法将它杀死,因为这是违反 Lua 脚本的原子性执行原则的。在这种情况下,唯一可行的办法是使用 SHUTDOWN NOSAVE 命令,通过停止整个 Redis 进程来停止脚本的运行,并防止不完整(half-written)的信息被写入数据库中。
返回值
执行成功返回 OK ,否则返回一个错误
示例
# 没有脚本在执行时
redis> SCRIPT KILL
(error) ERR No scripts in execution right now.
# 成功杀死脚本时
redis> SCRIPT KILL
OK
(1.30s)
# 尝试杀死一个已经执行过写操作的脚本,失败
redis> SCRIPT KILL
(error) ERR Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in an hard way using the SHUTDOWN NOSAVE command.
(1.69s)
以下是脚本被杀死之后,返回给执行脚本的客户端的错误:
redis> EVAL "while true do end" 0
(error) ERR Error running script (call to f_694a5fe1ddb97a4c6a1bf299d9537c7d3d0f84e7): Script killed by user with SCRIPT KILL...
(5.00s)