You need to enable JavaScript to run this app.
导航
Lua 脚本使用指南
最近更新时间:2024.07.30 16:56:13首次发布时间:2022.12.07 18:47:06

缓存数据库 Redis 版支持通过 Lua 脚本来处理 CAS(compare-and-swap)命令,满足 Redis 原子性操作需求,提升 Redis 性能。本文介绍通过 Redis 使用 Lua 脚本的基本语法与使用限制和建议。

Lua 脚本命令

下表列举了缓存数据库 Redis 版支持的 Lua 脚本命令和功能简介。

命令功能说明
EVAL执行给定的脚本和参数,并返回结果。
EVALSHA当通过 EVAL 命令执行较长的 Lua 脚本时,会占用较多带宽。为避免上述问题,您可以使用 EVALSHA 命令通过 Lua 脚本的 sha1 值来执行对应脚本。
SCRIPT LOAD将 Lua 脚本缓存至 Redis 实例中,但并不立即执行这个脚本,而是会返回该脚本的 sha1 值。
SCRIPT EXISTS通过指定脚本的 sha1 值,确认该值所对应的脚本是否已缓存至 Redis 实例中。支持同时传入多个脚本的 sha1 值进行确认,多个 sha1 值间用空格分隔。

SCRIPT KILL

终止正在运行的 Lua 脚本。
该命令主要用于终止运行时间过长的脚本,例如由于错误而进入无限循环的脚本。

SCRIPT FLUSH清空当前 Redis 实例中所有的 Lua 脚本缓存。

Lua 脚本命令语法

EVAL

  • 功能
    执行指定 Lua 脚本并返回对应结果。

  • 语法

    EVAL script numkeys [key [key ...]] [arg [arg ...]]
    

    参数具体说明如下表。

    参数说明

    script

    Lua 脚本的源代码。Redis 支持通过 KEYS[]ARGV[] 参数向脚本中传递数据,其中:

    • KEYS[]:指定 Redis Key 参数。索引从 1 开始,例如 KEYS[1]
    • ARGV[]:指定脚本参数。索引从 1 开始,例如 ARGV[1]

    numkeys

    指定 KEYS[] 参数的数量。
    实例架构不同,numkeys 的取值也不同。其中:

    • 未启用分片集群实例:numkeys 取值需大于等于 0。
    • 启用分片集群实例:numkeys 取值需大于等于 1。

    说明

    • 通过 EVAL 命令执行 Lua 脚本时,系统会同时将该脚本缓存至 Redis 实例中。关于 EVAL 命令的详细说明,请参见 EVAL
    • 推荐将脚本中所访问的 Key 通过 KEYS[] 参数显式传入,而不是将参数编码进脚本中,因为过多类似行为会导致实例内存使用量上升且无法及时回收,极端情况下会导致实例主库与备库内存溢出(Out of Memory),造成数据丢失。
  • 示例

    • 示例 1:通过 EVAL 命令执行如下 Lua 脚本,用于设置 Key=departmentvalue=Game 的字符串,具体命令如下。

      EVAl "return redis.call('SET',KEYS[1],ARGV[1])" 1 department Game
      

      返回示例如下。

      OK
      
    • 示例 2:通过 EVAL 命令执行如下 Lua 脚本,用于获取一个 Key=department 的字符串的值,具体命令如下。

      EVAl "return redis.call('GET',KEYS[1])" 1 department
      

      返回示例如下。

      "Game"
      

EVALSHA

  • 功能
    当通过 EVAL 命令执行较长的 Lua 脚本时,会占用较多带宽。为避免上述问题,您可以使用 EVALSHA 命令通过 Lua 脚本的 sha1 值来执行对应脚本。

  • 语法

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

    参数具体说明如下表。

    参数说明
    sha1Lua 脚本对应的 SHA1 校验和。

    numkeys

    指定 KEYS[] 参数的数量。实例架构不同,numkeys 的取值也不同。其中:

    • 未启用分片集群实例:numkeys 取值需大于等于 0。
    • 启用分片集群实例:numkeys 取值需大于等于 1。

    说明

    使用 EVALSHA 命令时,若 sha1 值对应的脚本未缓存至 Redis 中,Redis 会返回 NOSCRIPT No matching script. 报错。请先通过 EVAL 或 SCRIPT LOAD 命令将目标脚本缓存至 Redis 中再执行 EVALSHA 命令。关于 EVALSHA 命令的详细说明,请参见 EVALSHA

  • 示例

    EVALSHA 620cd258c2c9c88c9d10db67812ccf663d96bdc6 1 department
    

    返回结果示例如下。

    "Game"
    

SCRIPT LOAD

  • 功能
    将 Lua 脚本缓存至 Redis 实例中,但并不立即执行这个脚本,而是会返回该脚本的 sha1 值。

  • 语法

    SCRIPT LOAD script
    

    关于 SCRIPT LOAD 命令的详细说明,请参见 SCRIPT LOAD

  • 示例

    SCRIPT LOAD "return redis.call('GET',KEYS[1])" 1 department
    "return redis.call('GET',KEYS[1])" 1 department
    

    返回结果示例如下。

    "620cd258c2c9c88c9d10db67812ccf663d96bdc6"
    

SCRIPT EXISTS

  • 功能
    通过指定脚本的 sha1 值,确认该值所对应的脚本是否已缓存至 Redis 实例中。

  • 语法

    SCRIPT EXISTS sha1 [sha1 ...]
    

    说明

    • 支持同时传入多个脚本的 sha1 值进行确认,多个 sha1 值间用空格分隔。返回结果的取值范围如下:
      • 1:脚本已存在。
      • 0:脚本不存在。
    • 关于 SCRIPT EXISTS 命令的详细说明,请参见 SCRIPT EXISTS
  • 示例

    SCRIPT EXISTS 620cd258c2c9c88c9d10db67812ccf663d96bdc6 620cd258c2c9c88c9d10db67812ccf663d96bdc7
    

    返回结果示例如下。

    1) (integer) 1
    2) (integer) 0
    

SCRIPT KILL

  • 功能
    终止正在运行的 Lua 脚本。该命令主要用于终止运行时间过长的脚本,例如由于错误而进入无限循环的脚本。

  • 语法

    SCRIPT KILL
    

    说明

    • 为保障数据原子性,仅当指定脚本没有执行过任何写操作时,SCRIPT KILL 命令才会生效。
    • 执行 SCRIPT KILL 命令后,正在执行 Lua 脚本的客户端将会看到对应脚本命令所返回的错误。关于 SCRIPT KILL 命令的详细说明,请参见 SCRIPT KILL
  • 示例

    SCRIPT KILL
    

    返回结果示例如下。

    OK
    

SCRIPT FLUSH

  • 功能
    清空当前 Redis 实例中所有的 Lua 脚本缓存。

  • 语法

    SCRIPT FLUSH [ASYNC | SYNC]
    

    说明

    • Redis 支持指定执行 SCRIPT FLUSH 命令后缓存的刷新模式,取值范围如下:
      • SYNC(默认值):同步刷新缓存。
      • ASYNC:异步刷新缓存。
    • 该命令会清空当前 Redis 实例中所有的 Lua 脚本缓存,建议清空前先备份 Lua 脚本。关于 SCRIPT FLUSH 命令的详细说明,请参见 SCRIPT FLUSH
  • 示例

    SCRIPT FLUSH
    

    返回示例如下。

    OK
    

Lua 脚本使用限制

  • 缓存数据库 Redis 版的实例类型不同,使用 Lua 脚本时的限制也不同。其中:

    • 启用分片集群的 Redis 实例

      • 所有 Key 都应该由 KEYS 数组来传递;redis.call/pcall 中调用的 Redis 命令,Key 的位置必须是 KEYS 数组。
      • numkeys 的取值需大于等于 1。
      • 所有 Key 必须在一个 slot 上。
      • Lua 脚本中 Key 参数的个数默认上限为 100。当 Key 个数超过上限时,会出现 command arguments invalid 报错。若需要提高默认上限(最多可提升至 100000),请提交工单联系技术支持。
    • 不启用分片集群的 Redis 实例
      不启用分片集群的 Redis 实例在使用 Lua 脚本时,Lua 脚本中 Key 参数的个数默认上限为 100。当 Key 个数超过上限时,会出现 command arguments invalid 报错。若需要提高默认上限(最多可提升至 100000),请提交工单联系技术支持。

  • 缓存数据库 Redis 版限制了部分命令不可在 Lua 脚本中使用。更多关于 Lua 脚本中支持使用的命令详情,请参见命令支持

Lua 脚本使用建议

  • 建议将脚本中所访问的 Key 通过 KEYS[] 参数显式传入,而不是将参数编码进脚本中,因为过多类似行为会导致实例内存使用量上升且无法及时回收,极端情况下会导致实例主库与备库内存溢出(Out of Memory),造成数据丢失。
  • 建议在 Lua 脚本中增加 redis.replicate_commands(); 参数,来指定数据同步模式为基于实际命令的模式,避免出现主从数据不一致的问题。
  • 加载 Lua 脚本会耗费较多的计算资源,建议尽量复用 Lua 脚本,可以帮助降低网络开销和减少需要缓存的脚本数量。
  • 建议在 Lua 脚本中仅写入简单的命令操作,涉及原子性的复杂操作建议使用事务命令。
  • 建议不要在 Lua 脚本中写大量的循环,防止脚本执行超时或执行出错,甚至导致 Redis 实例卡死。
  • 建议不要在 Lua 脚本中使用一些非官方的 SDK(如 Redisson),防止出现一些未知的问题甚至风险。