Redis系列学习笔记13 Lua 脚本

Lua 脚本

在服务器端执行复杂的操作

尽管使用流水线可以一次发送多个命令,但是对于一个由多个命令组成的复杂操作来说,为了执行该操作而不断地重复发送相同的命令,这并不是最高效的做法,会对网络资源造成浪费。如果我们有办法避免重复地发送相同的命令,那么客户端就可以减少花在网络传输方面的时间,操作
就可以执行得更快。

脚本功能有以下好处:

  • 使用脚本可以直接在服务器端执行 Redis 命令,一般的数据处理操作可以直接使用 Lua 语言或者Lua 解释器提供的函数库来完成,不必再返回给客户端进行处理。
  • 所有脚本都是以事务的形式来执行的,脚本在执行过程中不会被其他工作打断,也不会引起任何竞争条件,完全可以使用 Lua 脚本来代替事务和乐观锁。
  • 所有脚本都是可重用的,也即是说,重复执行相同的操作时,只要调用储存在服务器内部的脚本缓存就可以了,不用重新发送整个脚本,从而尽可能地节约网络资源。

EVAL script numkeys key [key …] arg [arg …]

script 参数是要执行的 Lua 脚本。

numkeys 是脚本要处理的数据库键的数量,之后的 key [key …] 参数指定了脚本要处理的数据库键,被传入的键可以在脚本里面通过访问 KEYS 数组来取得,比如 KEYS[1] 就取出第一个输入的键,KEYS[2] 取出第二个输入的键,诸如此类。

arg [arg …] 参数指定了脚本要用到的参数,在脚本里面可以通过访问 ARGV 数组来获取这些参数。

显式地指定脚本里面用到的键是为了配合 Redis 集群对键的检查,如果不这样做的话,在集群里面使用脚本可能会出错。

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

通过调用 redis.call() 函数或者 redis.pcall() 函数,我们可以直接在 Lua 脚本里面执行 Redis 命令。

redis.call() 和 redis.pcall() 都可以用来执行 Redis 命令,它们的不同之处在于,当被执行的脚本出错时,redis.call() 会返回出错脚本的名字以及 EVAL 命令的错误信息,而 redis.pcall() 只返回 EVAL 命令的错误信息。换句话来说,在被执行的脚本出错时, redis.call() 可以提供更详细的错误信息,方便进行查错。

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

EVALSHA sha1 numkeys key [key …] arg [arg …]

SCRIPT EXISTS sha1 [sha1 …]

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

SCRIPT LOAD script

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

SCRIPT FLUSH

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

SCRIPT KILL

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

Redis 在 Lua 环境里面载入了一些常用的函数库,我们可以使用这些函数库,直接在脚本里面处理数据,它们分别是标准库:

  • base 库 :包含 Lua 的核心(core)函数,比如 assert、tostring、error、type 等。
  • string 库 :包含用于处理字符串的函数,比如 find、format、len、reverse 等。
  • table 库:包含用于处理表格的函数,比如 concat、insert、remove、sort 等。
  • math 库:包含常用的数学计算函数,比如 abs、sqrt、log 等。
  • debug 库:包含调试程序所需的函数,比如 sethook、gethook 等。

以及外部库

  • struct 库:在 C 语言的结构和 Lua 语言的值之间进行转换。
  • cjson 库:将 Lua 值转换为 JSON 对象,或者将 JSON 对象转换为 Lua 值。
  • cmsgpack 库:将 Lua 值编码为 MessagePack 格式,或者从 MessagePack 格式里面解码出 Lua值。

另外还有一个用于计算 sha1 值的外部函数 redis.sha1hex。

你可能感兴趣的:(Redis,redis)