Lua脚本

  1. 使用脚本可以直接在服 务器端执行 Redis 命令,一般的数据 处理操作可以直接使用 Lua 语言或者 Lua 解释器提供的函数 库来完成,不必再返回 给客户端进行处理。

  2. 所有脚本都是以事 务的形式来执行的,脚本在 执行过程中不会被其他工作打断,也不会引起任何 竞争条件,完全可以使用 Lua 脚本来代替事 务和乐观锁。

  3. 所有脚本都是可重用的,也即是 说,重复执行相同的操作 时,只要调用储存在服务器内部的脚本 缓存就可以了,不用重新 发送整个脚本,从而尽可能地 节约网络资源。

执行 Lua 脚本

1
EVAL script numkeys key [key ...] arg [arg ...]
  • script 参数是要执行的 Lua 脚本。
  • numkeys 是脚本要处理的数据库键的数量,之后的 key [key …] 参数指定了脚本要 处理的数据库键,被传入的键可以在脚本里面通 过访问 KEYS 数组来取得,比如 KEYS[1] 就取出第一个 输入的键,KEYS[2] 取出第二个输入的键,诸如此类。
  • arg [arg …] 参数指定了脚本要用到的参数,在脚本里面可以通 过访问 ARGV 数组来获取这些参数。显式地指定脚本里面用到的 键是为了配合 Redis 集群对键的检查,如果不这样做的话,在集群里面使用脚本可能会出 错。

另外,通过显式地指定脚本要用到的数据 库键以及相关参数,而不是将数据 库键和参数硬写在脚本里面,用户可以更方便地重用同一个脚本。

1
2
3
4
5
6
7
8
9
10
redis> EVAL "return redis.call('PING')" 0   # 在 Lua 脚本里面执行 PING 命令
PONG
redis> EVAL "return redis.call('DBSIZE')" 0 # 在 Lua 脚本里面执行 DBSIZE 命令
(integer) 4

# 在 Lua 脚本里面执行 GET 命令,取出键 msg 的值,并对值进行字符串拼接操作
redis> SET msg "hello world"
OK
redis> EVAL "return 'The message is: ' .. redis.call('GET', KEYS[1]) '" 1 msg
"The message is: hello world"

redis.call() 和 redis.pcall() 的区别

redis.call() 和 redis.pcall() 都可以用来执行 Redis 命令,它们的不同之处在于,当被执行的脚本出错时:

  • redis.call() 会返回出错脚本的名字以及 EVAL 命令的错误信息
  • redis.pcall() 只返回 EVAL 命令的错误信息。
1
2
3
4
5
6
redis> EVAL "return redis.call('NotExistsCommand')" 0
(error) ERR Error running script (call to f_ddabd662fa0a8e105765181ee7606562c1e6f1ce):
@user_script:1: @user_script: 1: Unknown Redis command called from Lua script

redis> EVAL "return redis.pcall('NotExistsCommand')" 0
(error) @user_script: 1: Unknown Redis command called from Lua script

换句话来说,在被执行的脚本出错时, redis.call() 可以提供更详细的错误信息,方便进行查错。

使用 EVALSHA 来减少网络资源损耗

任何 Lua 脚本,只要被 EVAL 命令执行过一次,就会被 储存到服务器的脚本缓存里面,用户只要通过 EVALSHA 命令,指定被 缓存脚本的 SHA1 值,就可以在不 发送脚本的情况下,再次 执行脚本:

1
EVALSHA sha1 numkeys key [key ...] arg [arg ...]

通过 SHA1 值来重用返回 ‘hello world’ 信息的脚本:

1
2
3
4
redis> EVAL "return 'hello world'" 0
"hello world"
redis> EVALSHA 5332031c6b470dc5a0dd9b4bf2030dea6d65de91 0
"hello world"

通过 SHA1 值来重用之前实现的 ZDECRBY 命令,这样就不用每次都 发送整个脚本了:

1
2
redis> EVALSHA 918130cae39ff0759b8256948742f77300a91cb2 1 salary 500 peter
(integer) 0

脚本管理命令

检查 sha1 值所代表的脚本是否已经被加入到脚本缓存里面,是的话返回 1 ,不是的话返回 0 。

1
SCRIPT EXISTS sha1 [sha1 ...]

将脚本储存到脚本缓存里面,等待将来 EVALSHA 使用。

1
SCRIPT LOAD script

清除脚本缓存储存的所有脚本。

1
SCRIPT FLUSH

杀死运行超时的脚本。如果脚本已经执行过写入操作,那么还需要使用 SHUTDOWN NOSAVE 命令来强制服务器不保存数据,以免错误的数据被保存到数据库里面。

1
SCRIPT KILL