Redis 可编程性

使用 Lua 和 Redis 函数扩展 Redis

Redis 提供了一个编程接口,允许您在服务器本身上执行自定义脚本。在 Redis 7 及更高版本中,您可以使用 Redis 函数 来管理和运行您的脚本。在 Redis 6.2 及更低版本中,您使用 EVAL 命令执行 Lua 脚本 来对服务器进行编程。

背景

根据 定义,Redis 是一个 “用于抽象数据类型的领域特定语言”。Redis 语言由其 命令 组成。大多数命令专门用于以不同方式操作核心 数据类型。在许多情况下,这些命令提供了开发人员在 Redis 中管理应用程序数据所需的所有功能。

Redis 中的 **可编程性** 意味着能够由服务器执行任意用户定义的逻辑。我们将此类逻辑片段称为 **脚本**。在我们的案例中,脚本支持在数据所在的地方处理数据,即 数据本地性。此外,将编程工作流嵌入 Redis 服务器中可以帮助减少网络流量并提高整体性能。开发人员可以使用此功能来实现强大的应用程序特定 API。此类 API 可以封装业务逻辑并跨多个键和不同数据结构维护数据模型。

用户脚本在 Redis 中由一个嵌入式的、沙盒化的脚本引擎执行。目前,Redis 支持单个脚本引擎,即 Lua 5.1 解释器。

有关完整文档,请参阅 Redis Lua API 参考 页面。

运行脚本

Redis 提供了两种运行脚本的方法。

首先,从 Redis 2.6.0 版本开始,EVAL 命令允许运行服务器端脚本。Eval 脚本提供了一种快速简便的方法,让 Redis 可以即时运行您的脚本。但是,使用它们意味着脚本逻辑是您应用程序的一部分(而不是 Redis 服务器的扩展)。每个运行脚本的应用程序实例都必须随时提供脚本源代码以供加载。这是因为脚本只由服务器缓存并且是易失性的。随着应用程序的增长,这种方法会变得越来越难以开发和维护。

其次,在 v7.0 中添加的 Redis 函数本质上是作为一等数据库元素的脚本。因此,函数将脚本与应用程序逻辑分离,并支持独立开发、测试和部署脚本。要使用函数,需要先加载它们,然后所有连接的客户端都可以使用它们。在这种情况下,将函数加载到数据库成为一项管理部署任务(例如,加载 Redis 模块),这将脚本与应用程序分离。

有关更多信息,请参阅以下页面

在运行脚本或函数时,Redis 保证其原子执行。脚本的执行会阻塞所有服务器活动,在其整个运行期间都是如此,与事务的语义类似。这些语义意味着脚本的所有效果要么尚未发生,要么已经发生。已执行脚本的阻塞语义在任何时间都适用于所有连接的客户端。

请注意,这种阻塞方法的潜在缺点是执行缓慢的脚本不是一个好主意。创建快速脚本并不难,因为脚本的开销非常低。但是,如果您打算在应用程序中使用慢速脚本,请注意,所有其他客户端都被阻塞,并且在脚本运行时无法执行任何命令。

只读脚本

只读脚本是指仅执行不修改 Redis 中任何键的命令的脚本。只读脚本可以通过在脚本中添加no-writes 标志或通过使用以下只读脚本命令变体之一来执行:EVAL_ROEVALSHA_ROFCALL_RO。它们具有以下属性

  • 它们始终可以在副本上执行。
  • 它们始终可以通过SCRIPT KILL命令终止。
  • 当 Redis 超出内存限制时,它们永远不会出现 OOM 错误。
  • 它们在写入暂停期间不会被阻塞,例如在协调故障转移期间发生的写入暂停。
  • 它们不能执行任何可能修改数据集的命令。
  • 目前,PUBLISHSPUBLISHPFCOUNT在脚本中也被视为写入命令,因为它们可能尝试将命令传播到副本和 AOF 文件。

除了所有只读脚本提供的优势之外,只读脚本命令还具有以下优点

  • 它们可用于配置 ACL 用户,使其只能执行只读脚本。
  • 许多客户端也更好地支持将只读脚本命令路由到副本,以便应用程序可以使用副本进行读取扩展。

只读脚本历史

只读脚本和只读脚本命令是在 Redis 7.0 中引入的。

  • 在 Redis 7.0.1 之前,PUBLISHSPUBLISHPFCOUNT在脚本中不被视为写入命令。
  • 在 Redis 7.0.1 之前,no-writes 标志不暗示allow-oom
  • 在 Redis 7.0.1 之前,no-writes 标志不允许脚本在写入暂停期间运行。

建议的方法是在需要上述功能之一之前,使用标准脚本命令以及no-writes 标志。

沙箱脚本上下文

Redis 将执行用户脚本的引擎置于沙箱中。沙箱试图防止意外误用,并减少服务器环境中潜在的威胁。

脚本绝不应该尝试访问 Redis 服务器的底层主机系统,例如文件系统、网络,或尝试执行 API 支持以外的任何其他系统调用。

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

最大执行时间

脚本受最大执行时间限制(默认设置为五秒)。此默认超时时间非常大,因为脚本通常在不到一毫秒的时间内运行。此限制是为了处理开发过程中意外创建的无限循环。

可以使用毫秒精度修改脚本可以执行的最大时间,可以通过redis.conf 或使用CONFIG SET命令来实现。影响最大执行时间的配置参数称为busy-reply-threshold

当脚本达到超时阈值时,Redis 不会自动终止它。这样做会违反 Redis 和脚本引擎之间的契约,该契约确保脚本是原子的。中断脚本的执行有可能导致数据集出现半写的更改。

因此,当脚本执行时间超过配置的超时时间时,会发生以下情况

  • Redis 记录脚本运行时间过长。
  • 它开始再次接受来自其他客户端的命令,但将对发送普通命令的所有客户端回复 BUSY 错误。在此状态下允许的唯一命令是SCRIPT KILLFUNCTION KILLSHUTDOWN NOSAVE
  • 可以使用SCRIPT KILLFUNCTION KILL命令终止仅执行只读命令的脚本。这些命令不会违反脚本语义,因为脚本尚未写入数据集。
  • 如果脚本已经执行了至少一个写入操作,则允许的唯一命令是SHUTDOWN NOSAVE,它会停止服务器,而不将当前数据集保存到磁盘(基本上,服务器被中止)。
RATE THIS PAGE
Back to top ↑