Redis Lua API 参考

在 Redis 中执行 Lua

Redis 内嵌了 Lua 5.1 解释器。解释器运行用户定义的 临时脚本函数。脚本在沙盒环境中运行,并且只能访问特定的 Lua 包。本页描述了执行环境中可用的包和 API。

沙盒环境

沙盒 Lua 环境旨在防止意外滥用并减少来自服务器环境的潜在威胁。

脚本绝不应尝试访问 Redis 服务器的底层主机系统。这包括文件系统、网络以及除 API 支持之外的任何其他系统调用尝试。

脚本应仅操作存储在 Redis 中的数据以及作为执行参数提供的数据。

全局变量和函数

沙盒 Lua 执行环境阻止声明全局变量和函数。阻止全局变量是为了确保脚本和函数不会尝试维护除存储在 Redis 中的数据之外的任何运行时上下文。在(有些不常见)需要在执行之间维护上下文的用例中,您应将上下文存储在 Redis 的键空间中。

尝试执行以下代码片段时,Redis 将返回“Script attempted to create global variable '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。其描述请参阅下文

KEYS 全局变量

  • 自版本:2.6.0
  • 在脚本中可用:是
  • 在函数中可用:否

重要提示: 为确保脚本在独立和集群部署中的正确执行,函数访问的所有键名必须显式作为输入键参数提供。脚本只能访问其名称作为输入参数提供的键。脚本绝不应访问使用程序生成名称的键,或基于数据库中存储的数据结构内容来访问键。

KEYS 全局变量仅适用于临时脚本。它预填充了所有键名输入参数。

ARGV 全局变量

  • 自版本:2.6.0
  • 在脚本中可用:是
  • 在函数中可用:否

ARGV 全局变量仅在临时脚本中可用。它预填充了所有常规输入参数。

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

以下演示了如何在临时脚本环境中拦截和处理运行时异常。

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 字段设置为该字符串。

以下代码的结果是 error1error2 在所有意图和目的上都是相同的

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 的表,该字段设置了一个简单的状态字符串。

以下代码的结果是 status1status2 在所有意图和目的上都是相同的

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_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.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 运行此脚本,结果将是只有键 AC 在副本和 AOF 上创建。

redis.replicate_commands()

  • 自版本:3.2.0
  • 截至版本:7.0.0
  • 在脚本中可用:是
  • 在函数中可用:否

此函数将脚本的复制模式从逐字复制切换到效果复制。您可以使用它来覆盖 Redis 在 7.0 版本之前使用的默认逐字脚本复制模式。

注意: 从 Redis v7.0 起,不再支持逐字脚本复制。默认且唯一支持的脚本复制模式是脚本效果复制。有关详细信息,请参阅 复制命令而非脚本

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 权限。

如果当前用户有权执行该命令(通过调用 redis.callredis.pcall),则返回值为布尔值 true;如果无权执行,则返回 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_namecallback 都是必需的。

使用示例

redis> FUNCTION LOAD "#!lua name=mylib\n redis.register_function{function_name='noop', callback=function() end, flags={ 'no-writes' }, description='Does nothing'}"

脚本标志

重要提示: 请谨慎使用脚本标志,误用可能会产生负面影响。请注意,Eval 脚本的默认设置与下面提到的函数的默认设置不同,请参阅 Eval 标志

注册函数或加载 Eval 脚本时,服务器不知道它如何访问数据库。默认情况下,Redis 假定所有脚本都读写数据。这导致以下行为

  1. 它们可以读写数据。
  2. 它们可以在集群模式下运行,但无法运行访问不同哈希槽键的命令。
  3. 拒绝在陈旧副本上执行,以避免不一致的读取。
  4. 拒绝在低内存下执行,以避免超过配置的阈值。

您可以使用以下标志并指示服务器以不同方式处理脚本的执行

  • no-writes:此标志表示脚本只读取数据,从不写入。

    默认情况下,Redis 将拒绝在只读副本上执行带有标志的脚本(带 shebang 的函数和 Eval 脚本),因为它们可能尝试执行写入操作。类似地,服务器不允许使用 FCALL_RO / EVAL_RO 调用脚本。最后,当数据持久性因磁盘错误而处于风险中时,执行也会被阻止。

    使用此标志允许执行脚本

    1. 使用 FCALL_RO / EVAL_RO
    2. 在只读副本上。
    3. 即使存在磁盘错误(Redis 无法持久化,因此拒绝写入)时也是如此。
    4. 当超过内存限制时,因为它意味着脚本不会增加内存消耗(参见下面的 allow-oom

    但是,请注意,如果脚本尝试调用写入命令,服务器将返回错误。另请注意,目前 PUBLISHSPUBLISHPFCOUNT 在脚本中也被视为写入命令,因为它们可能尝试将命令传播到副本和 AOF 文件。

    有关更多信息,请参阅 只读脚本

  • allow-oom:使用此标志允许脚本在服务器内存不足 (OOM) 时执行。

    除非使用此标志,否则当处于 OOM 状态时,Redis 将拒绝执行带有标志的脚本(带 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 服务器之间移动。

    当集群模式禁用时,此标志无效。

有关详细示例,请参阅 函数标志Eval 标志

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) 之后)

Lua 到 RESP2 的类型转换

以下类型转换规则适用于默认情况以及用户调用 HELLO 2 之后

还有一条附加的 Lua 到 Redis 的转换规则,它没有相应的 Redis 到 Lua 的转换规则

关于将 Lua 数据类型转换为 Redis 数据类型,还需要注意三个附加规则

  • Lua 只有一个数值类型,即 Lua number。整数和浮点数之间没有区别。因此,我们总是将 Lua number 转换为整型回复,如果存在小数部分,则将其移除。如果您想返回一个 Lua 浮点数,它应该作为一个字符串返回,就像 Redis 本身一样(例如,请参阅 ZSCORE 命令)。
  • 由于 Lua 的表语义,无法在 Lua 数组中简单地包含 nil 值。因此,当 Redis 将 Lua 数组转换为 RESP 时,一旦遇到 Lua nil 值,转换就会停止。
  • 当 Lua table 是一个包含键及其相应值的关联数组时,转换后的 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())的精确返回值,就像直接调用该命令会返回的那样。

以下示例展示了如何处理包含 nil 和键的浮点数和数组

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 被转换为整数 3somekey 键及其值被省略,并且字符串“bar”没有被返回,因为其前面有一个 nil 值。

RESP3 到 Lua 的类型转换

RESP3Redis 序列化协议 的一个新版本。从 Redis v6.0 开始,它可以作为可选选择。

正在执行的脚本可以在其执行期间调用 redis.setresp 函数,并切换用于返回 Redis 命令回复的协议版本(这些命令可以通过 redis.call()redis.pcall() 调用)。

一旦 Redis 的回复采用 RESP3 协议,所有 RESP2 到 Lua 的转换 规则都适用,并增加以下内容

  • RESP3 map reply -> Lua table,包含一个名为 map 的字段,其中包含一个 Lua table,表示 map 的字段和值。
  • RESP set reply -> Lua table,包含一个名为 set 的字段,其中包含一个 Lua table,表示 set 的元素作为字段,每个字段的值都是 Lua 布尔值 true
  • RESP3 null -> Lua nil
  • RESP3 true reply -> Lua 布尔值 true。
  • RESP3 false reply -> Lua 布尔值 false。
  • RESP3 double reply -> Lua table,包含一个名为 double 的字段,其中包含一个表示 double 值的 Lua number。
  • RESP3 big number reply -> Lua table,包含一个名为 big_number 的字段,其中包含一个表示 big number 值的 Lua string。
  • Redis verbatim string reply -> Lua table,包含一个名为 verbatim_string 的字段,其中包含一个 Lua table,该 table 有两个字段 stringformat,分别表示逐字字符串及其格式。

注意: RESP3 big numberverbatim strings 回复仅从 Redis v7.0 及更高版本开始支持。此外,目前 Redis Lua API 不支持 RESP3 的 attributesstreamed stringsstreamed aggregate data types

Lua 到 RESP3 的类型转换 无论脚本在调用 redis.call()redis.pcall() 时使用 [redis.setresp() 函数] 设置的回复协议版本是什么,用户都可以选择(使用 HELLO 3 命令)连接使用 RESP3。虽然传入客户端连接的默认协议是 RESP2,但脚本应尊重用户的偏好并返回适当类型的 RESP3 回复,因此在这种情况下,除了Lua 到 RESP2 类型转换 部分中指定的规则外,还适用以下规则。

Lua Boolean -> RESP3 Boolean reply(请注意,这与 RESP2 不同,在 RESP2 中,返回 Lua 布尔值 true 会向 Redis 客户端返回数字 1,返回 false 则返回 null

  • Lua table,包含一个名为 map 的字段,其值为关联 Lua table -> RESP3 map reply
  • Lua table,包含一个名为 set 的字段,其值为关联 Lua table -> RESP3 set reply。值可以设置为任何内容,反正都会被丢弃。
  • Lua table,包含一个名为 double 的字段,其值为关联 Lua table -> RESP3 double reply
  • 包含单个 double 字段的 Lua 表转换为关联的 Lua 表 -> RESP3 double 回复
  • Lua nil -> RESP3 null

但是,如果连接设置为使用 RESP2 协议,即使脚本回复的是 RESP3 类型响应,Redis 也会像处理常规命令一样自动执行 RESP3 到 RESP2 的回复转换。这意味着,例如,将 RESP3 map 类型返回给 RESP2 连接时,回复将被转换为扁平的 RESP2 数组,该数组由交替的字段名和其值组成,而不是一个 RESP3 map。

关于脚本的其他注意事项

在脚本中使用 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()

struct

  • 自版本:2.6.0
  • 在脚本中可用:是
  • 在函数中可用:是

struct 是一个用于在 Lua 中打包和解包类似 C 结构体的库。它提供了以下函数

struct 的所有函数都要求它们的第一个参数是一个 格式字符串

struct 格式

以下是 struct 函数的有效格式字符串

  • >: 大端字节序
  • <: 小端字节序
  • ![num]: 对齐
  • x: 填充
  • b/B: 有符号/无符号字节
  • h/H: 有符号/无符号 short
  • l/L: 有符号/无符号 long
  • T: size_t
  • i/In: 大小为 n 的有符号/无符号整数(默认为 int 的大小)
  • cn: n 个字符序列(来自/到字符串);打包时,n == 0 表示整个字符串;解包时,n == 0 表示使用之前读取的数字作为字符串的长度。
  • s: 零终止字符串
  • f: float
  • d: double
  • (空格): 忽略

struct.pack(x)

此函数根据值返回一个 struct 编码的字符串。它接受一个 struct 格式字符串 作为其第一个参数,后跟要编码的值。

使用示例

redis> EVAL "return struct.pack('HH', 1, 2)" 0
"\x01\x00\x02\x00"

struct.unpack(x)

此函数从 struct 解码并返回值。它接受一个 struct 格式字符串 作为其第一个参数,后跟编码后的 struct 字符串。

使用示例

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)

此函数返回 struct 的大小(以字节为单位)。它只接受一个 struct 格式字符串 作为参数。

使用示例

redis> EVAL "return struct.size('HH')" 0
(integer) 4

cjson

  • 自版本:2.6.0
  • 在脚本中可用:是
  • 在函数中可用:是

cjson 库提供了快速的 Lua JSON 编码和解码功能。它提供了这些函数。

cjson.encode(x)

此函数根据提供的 Lua 数据类型参数返回一个 JSON 编码的字符串。

使用示例

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 位数字,反之亦然。

评价此页面
回到顶部 ↑