Redis Lua API 参考
在Redis中执行Lua
Redis 包含一个嵌入式的 Lua 5.1 解释器。 该解释器运行用户定义的 临时脚本 和 函数。脚本在沙盒环境中运行,并且只能访问特定的 Lua 包。本页描述了执行上下文中可用的包和 API。
沙盒上下文
沙盒化的Lua上下文旨在防止意外误用并减少来自服务器环境的潜在威胁。
脚本永远不应该尝试访问Redis服务器的底层主机系统。 这包括文件系统、网络以及任何尝试执行系统调用的行为,除了API支持的那些。
脚本应仅对存储在Redis中的数据以及作为执行参数提供的数据进行操作。
全局变量和函数
沙盒化的 Lua 执行上下文阻止了全局变量和函数的声明。 阻止全局变量的声明是为了确保脚本和函数不会尝试维护除存储在 Redis 中的数据之外的任何运行时上下文。 在(较为不常见的)用例中,如果需要在执行之间维护上下文, 你应该将上下文存储在 Redis 的键空间中。
Redis 在执行以下代码片段时,将返回一个“脚本尝试创建全局变量 'my_global_variable'”的错误:
my_global_variable = 'some value'
同样适用于以下全局函数声明:
function my_global_function()
-- Do something amazing
end
当您的脚本尝试访问在运行时的上下文中未定义的任何全局变量时,您也会收到类似的错误:
-- The following will surely raise an error
return an_undefined_global_variable
相反,所有变量和函数的定义都需要声明为局部变量。 为此,你需要在声明前加上local关键字。 例如,以下代码片段将被Redis视为完全有效:
local my_local_variable = 'some value'
local function my_local_function()
-- Do something else, but equally amazing
end
注意: 沙盒试图阻止使用全局变量。 使用Lua的调试功能或其他方法(如更改用于实现全局变量保护的元表)来绕过沙盒并不难。 然而,意外绕过保护是困难的。 如果用户干扰了Lua的全局状态,AOF和复制的一致性就无法保证。 换句话说,就是不要这样做。
导入的 Lua 模块
在沙盒执行环境中不支持使用导入的Lua模块。
沙盒执行环境通过禁用Lua的require函数来阻止加载模块。
Redis 附带的并且可以在脚本中使用的唯一库列在 运行时库 部分下。
运行时全局变量
虽然沙盒阻止用户声明全局变量,但执行上下文已经预填充了几个这样的变量。
redis 单例
redis 单例是一个可以从所有脚本访问的对象实例。 它提供了从脚本与 Redis 交互的 API。 其描述如下 below。
KEYS 全局变量
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:否
重要提示: 为了确保脚本在独立和集群部署中的正确执行,函数访问的所有键名必须明确作为输入键参数提供。 脚本应仅访问那些名称作为输入参数提供的键。 脚本绝不应访问那些通过编程生成的名称或基于数据库中存储的数据结构内容的键。
KEYS 全局变量仅适用于 ephemeral scripts。 它预先填充了所有键名输入参数。
ARGV 全局变量
- 自版本起:2.6.0
- 脚本中可用:是
- 在函数中可用:否
ARGV 全局变量仅在 ephemeral scripts 中可用。 它预先填充了所有常规输入参数。
redis 对象
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
Redis Lua 执行上下文始终提供一个名为 redis 的单例对象实例。 redis 实例使脚本能够与运行它的 Redis 服务器进行交互。 以下是 redis 对象实例提供的 API。
redis.call(command [,arg...])
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
redis.call() 函数调用给定的 Redis 命令并返回其响应。
它的输入是命令和参数,一旦调用,它会在 Redis 中执行命令并返回响应。
例如,我们可以从脚本中调用ECHO命令并返回其回复,如下所示:
return redis.call('ECHO', 'Echo, echo... eco... o...')
如果redis.call()触发了运行时异常,原始异常会自动作为错误返回给用户。
因此,尝试执行以下临时脚本将会失败并生成运行时异常,因为ECHO只接受一个参数:
redis> EVAL "return redis.call('ECHO', 'Echo,', 'echo... ', 'eco... ', 'o...')" 0
(error) ERR Wrong number of args calling Redis command from script script: b0345693f4b77517a711221050e76d24ae60b7f7, on @user_script:1.
请注意,调用可能因各种原因失败,请参阅低内存条件下的执行和脚本标志
要处理Redis运行时错误,请使用redis.pcall()代替。
redis.pcall(command [,arg...])
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
此函数用于处理由Redis服务器引发的运行时错误。
redis.pcall() 函数的行为与 redis.call() 完全相同,除了它:
- 总是返回一个回复。
- 从不抛出运行时异常,并在服务器抛出运行时异常时返回一个
redis.error_reply来代替。
以下演示了如何在临时脚本的上下文中使用redis.pcall()来拦截和处理运行时异常。
local reply = redis.pcall('ECHO', unpack(ARGV))
if reply['err'] ~= nil then
-- Handle the error sometime, but for now just log it
redis.log(redis.LOG_WARNING, reply['err'])
reply['err'] = 'ERR Something is wrong, but no worries, everything is under control'
end
return reply
使用多个参数评估此脚本将返回:
redis> EVAL "..." 0 hello world
(error) ERR Something is wrong, but no worries, everything is under control
redis.error_reply(x)
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
这是一个辅助函数,返回一个错误回复。 该辅助函数接受一个字符串参数,并返回一个Lua表,其中err字段设置为该字符串。
以下代码的结果是,error1 和 error2 在所有意图和目的上都是相同的:
local text = 'ERR My very special error'
local reply1 = { err = text }
local reply2 = redis.error_reply(text)
因此,这两种形式都是有效的,用于从脚本返回错误回复:
redis> EVAL "return { err = 'ERR My very special table error' }" 0
(error) ERR My very special table error
redis> EVAL "return redis.error_reply('ERR My very special reply error')" 0
(error) ERR My very special reply error
要返回Redis状态回复,请参考redis.status_reply()。
有关返回其他响应类型的信息,请参阅数据类型转换。
注意:
按照惯例,Redis使用错误字符串的第一个单词作为特定错误的唯一错误代码,或使用ERR表示通用错误。
建议脚本遵循此惯例,如上例所示,但这不是强制性的。
redis.status_reply(x)
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
这是一个辅助函数,返回一个简单的字符串回复。 "OK" 是标准 Redis 状态回复的一个例子。 Lua API 将状态回复表示为具有单个字段的表,ok,设置为一个简单的状态字符串。
以下代码的结果是,status1 和 status2 在所有意图和目的上都是相同的:
local text = 'Frosty'
local status1 = { ok = text }
local status2 = redis.status_reply(text)
因此,这两种形式都是有效的,用于从脚本返回状态回复:
redis> EVAL "return { ok = 'TICK' }" 0
TICK
redis> EVAL "return redis.status_reply('TOCK')" 0
TOCK
对于返回Redis错误回复,请参考redis.error_reply()。
有关返回其他响应类型的信息,请参阅数据类型转换。
redis.sha1hex(x)
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
此函数返回其单个字符串参数的SHA1十六进制摘要。
例如,您可以获取空字符串的SHA1摘要:
redis> EVAL "return redis.sha1hex('')" 0
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
redis.log(level, message)
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
此函数写入Redis服务器日志。
它期望有两个输入参数:日志级别和消息。 消息是要写入日志文件的字符串。 日志级别可以是以下之一:
redis.LOG_DEBUGredis.LOG_VERBOSEredis.LOG_NOTICEredis.LOG_WARNING
这些级别映射到服务器的日志级别。
日志仅记录级别等于或高于服务器的loglevel配置指令的消息。
以下代码片段:
redis.log(redis.LOG_WARNING, 'Something is terribly wrong')
将在您的服务器日志中生成类似于以下内容的行:
[32343] 22 Mar 15:21:39 # Something is terribly wrong
redis.setresp(x)
- 自版本:6.0.0
- 在脚本中可用:是
- 在函数中可用:是
此函数允许执行脚本在Redis序列化协议(RESP)版本之间切换,用于redis.call()和redis.pcall()返回的回复。
它期望一个单一的数字参数作为协议的版本。
默认协议版本是2,但可以切换到版本3。
以下是一个切换到 RESP3 回复的示例:
redis.setresp(3)
请参考数据类型转换以获取有关类型转换的更多信息。
redis.set_repl(x)
- 自版本起:3.2.0
- 在脚本中可用:是
- 在函数中可用:否
注意: 此功能仅在采用脚本效果复制时可用。 在使用逐字脚本复制时调用它会导致错误。 从Redis版本2.6.0开始,脚本是逐字复制的,这意味着脚本的源代码被发送给副本执行并存储在AOF中。 在版本3.2.0中添加的另一种复制模式允许仅复制脚本的效果。 从Redis版本7.0开始,不再支持脚本复制,唯一可用的复制模式是脚本效果复制。
警告: 这是一个高级功能。滥用可能会通过违反Redis主节点、其副本和AOF内容之间保持相同逻辑内容的契约而造成损害。
此函数允许脚本控制其效果如何传播到副本和之后的AOF。 脚本的效果是它调用的Redis写命令。
默认情况下,脚本执行的所有写命令都会被复制。然而,有时更好地控制这种行为可能会有所帮助。例如,当仅在主节点中存储中间值时,可能就是这种情况。
考虑一个脚本,它使用SUNIONSTORE将两个集合的交集存储在一个临时键中。
然后从交集中随机选取五个元素(SRANDMEMBER)并将它们(SADD)存储在另一个集合中。
最后,在返回之前,它会删除存储两个源集合交集的临时键。
在这种情况下,只需要复制包含五个随机选择元素的新集合。
复制SUNIONSTORE命令和临时键的DEL操作是不必要且浪费的。
redis.set_repl() 函数指示服务器如何处理后续的写命令在复制方面。
它接受一个输入参数,该参数只能是以下之一:
redis.REPL_ALL: 将效果复制到AOF和副本。redis.REPL_AOF: 仅将效果复制到AOF。redis.REPL_REPLICA: 仅将效果复制到副本。redis.REPL_SLAVE: 与REPL_REPLICA相同,为了向后兼容而保留。redis.REPL_NONE: 完全禁用效果复制。
默认情况下,当脚本开始执行时,脚本引擎被初始化为redis.REPL_ALL设置。
您可以在脚本执行期间的任何时候调用redis.set_repl()函数来在不同的复制模式之间切换。
一个简单的示例如下:
redis.replicate_commands() -- Enable effects replication in versions lower than Redis v7.0
redis.call('SET', KEYS[1], ARGV[1])
redis.set_repl(redis.REPL_NONE)
redis.call('SET', KEYS[2], ARGV[2])
redis.set_repl(redis.REPL_ALL)
redis.call('SET', KEYS[3], ARGV[3])
如果你通过调用EVAL "..." 3 A B C 1 2 3来运行这个脚本,结果将是在副本和AOF上只创建键A和C。
redis.replicate_commands()
- 自版本起:3.2.0
- 直到版本:7.0.0
- 在脚本中可用:是
- 在函数中可用:否
此函数将脚本的复制模式从逐字复制切换到效果复制。 您可以使用它来覆盖Redis在7.0版本之前使用的默认逐字脚本复制模式。
注意:
从Redis v7.0开始,不再支持逐字脚本复制。
默认且唯一支持的脚本复制模式是脚本效果复制。
有关更多信息,请参阅Replicating commands instead of scripts
redis.breakpoint()
- 自版本起:3.2.0
- 在脚本中可用:是
- 在函数中可用:否
此函数在使用Redis Lua调试器时触发断点。
redis.debug(x)
- 自版本起:3.2.0
- 在脚本中可用:是
- 在函数中可用:否
此函数在Redis Lua调试器控制台中打印其参数。
redis.acl_check_cmd(command [,arg...])
- 自版本起:7.0.0
- 在脚本中可用:是
- 在函数中可用:是
此函数用于检查当前运行脚本的用户是否具有ACL权限以使用给定的参数执行给定的命令。
返回值是一个布尔值 true,表示当前用户有权限执行该命令(通过调用 redis.call 或 redis.pcall),或者返回 false,表示他们没有权限。
如果传递的命令或其参数无效,该函数将引发错误。
redis.register_function
- 自版本起:7.0.0
- 在脚本中可用:否
- 在函数中可用:是
此功能仅在FUNCTION LOAD命令的上下文中可用。
调用时,它会将函数注册到加载的库中。
该函数可以使用位置参数或命名参数调用。
位置参数: redis.register_function(name, callback)
redis.register_function的第一个参数是一个表示函数名称的Lua字符串。
redis.register_function的第二个参数是一个Lua函数。
使用示例:
redis> FUNCTION LOAD "#!lua name=mylib\n redis.register_function('noop', function() end)"
命名参数: redis.register_function{function_name=name, callback=callback, flags={flag1, flag2, ..}, description=description}
命名参数变体接受以下参数:
- function_name: 函数的名称。
- callback: 函数的回调。
- flags: 一个字符串数组,每个字符串是一个函数标志(可选)。
- description: 函数的描述(可选)。
无论是 function_name 还是 callback 都是必需的。
使用示例:
redis> FUNCTION LOAD "#!lua name=mylib\n redis.register_function{function_name='noop', callback=function() end, flags={ 'no-writes' }, description='Does nothing'}"
脚本标志
重要提示: 请谨慎使用脚本标志,如果误用可能会产生负面影响。 请注意,Eval脚本的默认设置与下面提到的函数的默认设置不同,请参阅Eval Flags
当你注册一个函数或加载一个Eval脚本时,服务器不知道它如何访问数据库。 默认情况下,Redis假设所有脚本都会读写数据。 这会导致以下行为:
- 他们可以读取和写入数据。
- 它们可以在集群模式下运行,但不能运行访问不同哈希槽键的命令。
- 为了防止读取不一致,拒绝在过时的副本上执行。
- 在内存不足的情况下拒绝执行,以避免超过配置的阈值。
您可以使用以下标志并指示服务器以不同的方式处理脚本的执行:
-
no-writes: 此标志表示脚本仅读取数据但从不写入。默认情况下,Redis会拒绝执行带有标志的脚本(带有shebang的函数和Eval脚本)针对只读副本,因为它们可能会尝试执行写入操作。 同样,服务器将不允许使用
FCALL_RO/EVAL_RO调用脚本。 最后,当由于磁盘错误导致数据持久性受到威胁时,执行也会被阻止。使用此标志允许执行脚本:
但是,请注意,如果脚本尝试调用写入命令,服务器将返回错误。 还要注意,目前
PUBLISH、SPUBLISH和PFCOUNT在脚本中也被视为写入命令,因为它们可能会尝试将命令传播到副本和AOF文件。更多信息请参考只读脚本
-
allow-oom: 使用此标志以允许脚本在服务器内存不足(OOM)时执行。除非使用此标志,否则Redis在OOM状态下将拒绝执行带有标志的脚本(带有shebang的函数和Eval脚本)。 此外,当您使用此标志时,脚本可以调用任何Redis命令,包括在此状态下通常不允许的命令。 指定
no-writes或使用FCALL_RO/EVAL_RO也意味着脚本可以在OOM状态下运行(无需指定allow-oom) -
allow-stale: 一个标志,当replica-serve-stale-data配置设置为no时,允许在过期的副本上运行标记的脚本(带有shebang的函数和Eval脚本)。Redis可以设置为防止使用旧数据导致的数据一致性问题,通过让过期的副本返回运行时错误。 对于不访问数据的脚本,可以设置此标志以允许过期的Redis副本运行脚本。 但请注意,脚本仍然无法执行任何访问过期数据的命令。
-
no-cluster: 该标志会导致脚本在Redis集群模式下返回错误。Redis允许脚本在独立模式和集群模式下执行。 设置此标志可防止在集群节点上执行脚本。
-
allow-cross-slot-keys: 允许脚本访问来自多个槽的键的标志。Redis 通常阻止任何单个命令访问哈希到多个槽的键。 此标志允许脚本打破此规则,并访问脚本中访问多个槽的键。 脚本声明的键仍然始终需要哈希到单个槽。 不鼓励访问来自多个槽的键,因为应用程序应设计为一次仅访问来自单个槽的键,从而允许槽在 Redis 服务器之间移动。
当集群模式被禁用时,此标志无效。
请参考Function Flags和Eval Flags以获取详细示例。
redis.REDIS_VERSION
- 自版本起:7.0.0
- 在脚本中可用:是
- 在函数中可用:是
返回当前Redis服务器版本作为Lua字符串。
回复的格式为MM.mm.PP,其中:
- MM: 是主版本号。
- mm: 是次要版本。
- PP: 是补丁级别。
redis.REDIS_VERSION_NUM
- 自版本起:7.0.0
- 在脚本中可用:是
- 在函数中可用:是
返回当前Redis服务器版本号。
回复是一个十六进制值,结构为0x00MMmmPP,其中:
- MM: 是主版本号。
- mm: 是次要版本。
- PP: 是补丁级别。
数据类型转换
除非引发运行时异常,redis.call() 和 redis.pcall() 将返回执行命令的回复给 Lua 脚本。
Redis 从这些函数返回的回复会自动转换为 Lua 的原生数据类型。
同样地,当Lua脚本使用return关键字返回回复时,该回复会自动转换为Redis的协议。
换句话说;Redis的回复和Lua的数据类型之间存在一对一的映射关系,Lua的数据类型和Redis协议的数据类型之间也存在一对一的映射关系。 底层设计是这样的,如果一个Redis类型被转换为Lua类型,然后再转换回Redis类型,结果与初始值相同。
从Redis协议回复(即来自redis.call()和redis.pcall()的回复)到Lua数据类型的转换取决于脚本使用的Redis序列化协议版本。
脚本执行期间的默认协议版本是RESP2。
脚本可以通过调用redis.setresp()函数来切换回复的协议版本。
从脚本返回的Lua数据类型进行类型转换取决于用户选择的协议(参见HELLO命令)。
以下部分描述了根据协议版本的Lua和Redis之间的类型转换规则。
RESP2 到 Lua 类型转换
以下类型转换规则默认适用于执行上下文,以及在调用 redis.setresp(2) 之后:
- RESP2 整数回复 -> Lua 数字
- RESP2 bulk string reply -> Lua 字符串
- RESP2 array reply -> Lua 表(可能嵌套其他 Redis 数据类型)
- RESP2 状态回复 -> 包含状态字符串的单个 ok 字段的 Lua 表
- RESP2错误回复 -> 包含错误字符串的单个err字段的Lua表
- RESP2 null bulk reply 和 RESP2 null multi-bulk reply -> Lua false 布尔类型
Lua 到 RESP2 类型转换
以下类型转换规则默认适用,并且在用户调用HELLO 2后也适用:
- Lua 数字 -> RESP2 整数回复(数字被转换为整数)
- Lua 字符串 -> RESP2 批量字符串回复
- Lua 表(索引,非关联数组) -> RESP2 数组回复(在表中遇到的第一个 Lua
nil值处截断,如果有的话) - 带有单个ok字段的Lua表 -> RESP2状态回复
- 带有单个err字段的Lua表 -> RESP2错误回复
- Lua 布尔值 false -> RESP2 空批量回复
有一个额外的Lua到Redis的转换规则,没有相应的Redis到Lua的转换规则:
- Lua 布尔值
true-> RESP2 整数回复 值为 1。
关于将Lua转换为Redis数据类型,还有三个额外的规则需要注意:
- Lua 只有一种数值类型,即 Lua 数字。
整数和浮点数之间没有区别。
因此,我们总是将 Lua 数字转换为整数回复,如果有小数部分,则去除小数部分。
如果你想返回一个 Lua 浮点数,应该将其作为字符串返回,
就像 Redis 本身所做的那样(例如,参见
ZSCORE命令)。 - 由于Lua的表语义,在Lua数组中没有简单的方法来包含nil值。
因此,当Redis将Lua数组转换为RESP时,遇到Lua的
nil值时转换会停止。 - 当Lua表是一个包含键及其相应值的关联数组时,转换后的Redis回复将不会包含它们。
Lua 到 RESP2 类型转换示例:
redis> EVAL "return 10" 0
(integer) 10
redis> EVAL "return { 1, 2, { 3, 'Hello World!' } }" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
1) "Hello World!"
redis> EVAL "return redis.call('get','foo')" 0
"bar"
最后一个示例演示了在Lua中接收并返回redis.call()(或redis.pcall())的确切返回值,就像直接调用该命令时返回的那样。
以下示例展示了如何处理包含nils和keys的浮点数和数组:
redis> EVAL "return { 1, 2, 3.3333, somekey = 'somevalue', 'foo', nil , 'bar' }" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"
如你所见,浮点值3.333被转换为整数3,somekey键及其值被省略,并且字符串"bar"没有被返回,因为前面有一个nil值。
RESP3 到 Lua 类型转换
RESP3 是 Redis 序列化协议 的新版本。 从 Redis v6.0 开始,它作为一个可选的选择提供。
正在执行的脚本可以在执行过程中调用redis.setresp函数,并切换用于从Redis命令返回回复的协议版本(可以通过redis.call()或redis.pcall()调用)。
一旦Redis的回复采用RESP3协议,所有RESP2到Lua的转换规则都适用,并有以下附加内容:
- RESP3 映射回复 -> 包含单个 map 字段的 Lua 表,该字段包含表示映射字段和值的 Lua 表。
- RESP set reply -> 包含单个set字段的Lua表,该字段包含一个Lua表,表示集合的元素作为字段,每个字段的Lua布尔值为
true。 - RESP3 null -> Lua
nil. - RESP3 true reply -> Lua 真布尔值。
- RESP3 false reply -> Lua false 布尔值。
- RESP3 double reply -> 包含一个double字段的Lua表,该字段包含一个表示双精度值的Lua数字。
- RESP3 大数回复 -> 包含单个 big_number 字段的 Lua 表,该字段包含表示大数值的 Lua 字符串。
- Redis verbatim string reply -> 包含单个verbatim_string字段的Lua表,该字段包含一个具有两个字段的Lua表,string和format,分别表示逐字字符串及其格式。
注意: RESP3 的 大数 和 原样字符串 回复仅在 Redis v7.0 及以上版本中支持。 此外,目前 Redis Lua API 不支持 RESP3 的 属性、流式字符串 和 流式聚合数据类型。
Lua 到 RESP3 类型转换
无论脚本在调用redis.call()或redis.pcall()时选择为回复设置的协议版本(通过[redis.setresp()函数]),用户可以选择使用RESP3(通过HELLO 3命令)进行连接。
尽管传入客户端连接的默认协议是RESP2,脚本应尊重用户的偏好并返回适当类型的RESP3回复,因此在这种情况下,除了Lua到RESP2类型转换部分中指定的规则外,还应遵循以下规则。
- Lua 布尔值 -> RESP3 布尔回复(注意,这与 RESP2 相比有所变化,在 RESP2 中,返回 Lua 布尔值
true会向 Redis 客户端返回数字 1,而返回false则会返回null。 - Lua 表,其中包含一个设置为关联 Lua 表的 map 字段 -> RESP3 映射回复。
- 带有单个set字段的Lua表,该字段设置为关联的Lua表 -> RESP3集合回复。值可以设置为任何内容,但无论如何都会被丢弃。
- 将具有单个double字段的Lua表转换为关联Lua表 -> RESP3 double reply。
- Lua nil -> RESP3 null.
然而,如果连接设置为使用RESP2协议,即使脚本回复的是RESP3类型的响应,Redis也会像处理常规命令一样自动将回复从RESP3转换为RESP2。 这意味着,例如,将RESP3的映射类型返回给RESP2连接将导致回复被转换为一个扁平的RESP2数组,该数组由交替的字段名及其值组成,而不是RESP3的映射。
关于脚本的附加说明
在脚本中使用 SELECT
你可以从你的Lua脚本中调用SELECT命令,就像你可以使用任何普通的客户端连接一样。
然而,在Redis版本2.8.11和2.8.12之间,行为的一个微妙方面发生了变化。
在Redis版本2.8.12之前,Lua脚本选择的数据库被设置为调用它的客户端连接的当前数据库。
从Redis版本2.8.12开始,Lua脚本选择的数据库只影响脚本的执行上下文,并且不会修改调用脚本的客户端所选择的数据库。
由于旧的行为本质上与Redis的复制不兼容并引入了错误,因此在补丁级别发布之间需要进行这种语义更改。
运行时库
Redis Lua 运行时环境总是预加载了几个库。
以下标准Lua库可供使用:
此外,以下外部库已加载并可被脚本访问:
os 库
- 自版本起:7.4
- 在脚本中可用:是
- 在函数中可用:是
os 提供了一组用于处理日期、时间和系统命令的函数。 更多详细信息可以在操作系统设施中找到。 请注意,出于沙箱安全的考虑,目前仅暴露了以下 os 函数:
os.clock()
结构体 库
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
struct 是一个用于在 Lua 中打包和解包类似 C 语言结构的库。 它提供了以下函数:
所有struct的函数都期望它们的第一个参数是一个格式字符串。
结构体 格式
以下是struct函数的有效格式字符串:
>: 大端序<: 小端序![num]: 对齐x: 填充b/B: 有符号/无符号字节h/H: 有符号/无符号短整型l/L: 有符号/无符号长整型T: size_ti/In: 大小为 n 的有符号/无符号整数(默认为 int 的大小)cn: 由n个字符组成的序列(来自/到一个字符串);打包时,n == 0 表示整个字符串;解包时,n == 0 表示使用之前读取的数字作为字符串的长度。s: 以零结尾的字符串f: 浮点数d: 双精度浮点数(空格): 忽略
struct.pack(x)
此函数从值返回一个结构编码的字符串。 它接受一个结构格式字符串作为其第一个参数,后面跟着要编码的值。
使用示例:
redis> EVAL "return struct.pack('HH', 1, 2)" 0
"\x01\x00\x02\x00"
struct.unpack(x)
此函数返回从结构体解码的值。 它接受一个结构体格式字符串作为第一个参数,后面跟着编码的结构体字符串。
使用示例:
redis> EVAL "return { struct.unpack('HH', ARGV[1]) }" 0 "\x01\x00\x02\x00"
1) (integer) 1
2) (integer) 2
3) (integer) 5
struct.size(x)
此函数返回结构体的大小,以字节为单位。 它接受一个结构体格式字符串作为其唯一参数。
使用示例:
redis> EVAL "return struct.size('HH')" 0
(integer) 4
cjson 库
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
cjson 库提供了从 Lua 快速进行 JSON 编码和解码的功能。它提供了以下函数。
cjson.encode(x)
此函数返回一个JSON编码的字符串,用于作为其参数提供的Lua数据类型。
使用示例:
redis> EVAL "return cjson.encode({ ['foo'] = 'bar' })" 0
"{\"foo\":\"bar\"}"
cjson.decode(x) {#cjson.decode()}
此函数从作为参数提供的JSON编码字符串返回Lua数据类型。
使用示例:
redis> EVAL "return cjson.decode(ARGV[1])['foo']" 0 '{"foo":"bar"}'
"bar"
cmsgpack 库
- 自版本起:2.6.0
- 在脚本中可用:是
- 在函数中可用:是
cmsgpack 库提供了从 Lua 进行快速的 MessagePack 编码和解码。它提供了以下函数。
cmsgpack.pack(x) {#cmsgpack.pack()}
此函数返回作为参数传递的Lua数据类型的打包字符串编码。
使用示例:
redis> EVAL "return cmsgpack.pack({'foo', 'bar', 'baz'})" 0
"\x93\xa3foo\xa3bar\xa3baz"
cmsgpack.unpack(x) {#cmsgpack.unpack()}
此函数返回从其输入字符串参数解码后的解包值。
使用示例:
redis> EVAL "return cmsgpack.unpack(ARGV[1])" 0 "\x93\xa3foo\xa3bar\xa3baz"
1) "foo"
2) "bar"
3) "baz"
bit 库
- 自版本起:2.8.18
- 在脚本中可用:是
- 在函数中可用:是
bit 库提供了对数字的位操作。 其文档位于 Lua BitOp 文档 它提供了以下函数。
bit.tobit(x) {#bit.tobit()}
将数字规范化为位操作的数值范围并返回它。
使用示例:
redis> EVAL 'return bit.tobit(1)' 0
(integer) 1
bit.tohex(x [,n]) {#bit.tohex()}
将其第一个参数转换为十六进制字符串。十六进制数字的数量由可选的第二个参数的绝对值给出。
使用示例:
redis> EVAL 'return bit.tohex(422342)' 0
"000671c6"
bit.bnot(x) {#bit.bnot()}
返回其参数的按位非。
bit.bnot(x) bit.bor(x1 [,x2...]), bit.band(x1 [,x2...]) 和 bit.bxor(x1 [,x2...])
返回其所有参数的按位或、按位与或按位异或。 请注意,允许有两个以上的参数。
使用示例:
redis> EVAL 'return bit.bor(1,2,4,8,16,32,64,128)' 0
(integer) 255
bit.lshift(x, n), bit.rshift(x, n) 和 bit.arshift(x, n)
返回其第一个参数的按位逻辑左移、按位逻辑右移或按位算术右移,移动的位数由第二个参数给出。
bit.rol(x, n) 和 bit.ror(x, n)
返回其第一个参数的按位左旋转或按位右旋转,旋转的位数由第二个参数给出。 在一侧移出的位会在另一侧移回。
bit.bswap(x) {#bit.bswap()}
交换其参数的字节并返回它。 这可以用于将小端序的32位数字转换为大端序的32位数字,反之亦然。