Valkey 提供了一个编程接口,允许您在服务器本身执行自定义脚本。您可以使用函数来创建、管理和运行脚本。您还可以使用带有 EVAL 命令的 Lua 脚本来对服务器进行编程。
背景
Valkey 是一种“用于抽象数据类型的领域特定语言”。Valkey 所说的语言由其命令组成。大多数命令专门以不同方式操作核心数据类型。在许多情况下,这些命令提供了开发人员管理 Valkey 中应用程序数据所需的所有功能。
Valkey 中的可编程性一词,意味着服务器能够执行任意用户定义的逻辑。我们将这些逻辑片段称为脚本。在我们的案例中,脚本能够就地处理数据,即数据局部性。此外,在 Valkey 服务器中负责地嵌入编程工作流有助于减少网络流量并提高整体性能。开发人员可以利用此功能实现健壮的、特定于应用程序的 API。此类 API 可以封装业务逻辑并在多个键和不同数据结构之间维护数据模型。
用户脚本由 Valkey 中嵌入的沙盒脚本引擎执行。目前,Valkey 支持单一脚本引擎:Lua 5.1 解释器。
请参阅Valkey Lua API 参考页面以获取完整文档。
运行脚本
Valkey 提供了两种运行脚本的方式。
首先,EVAL
命令支持运行服务器端脚本。Eval 脚本提供了一种快速直接的方式,让 Valkey 临时运行您的脚本。但是,使用它们意味着脚本逻辑是您应用程序的一部分(而不是 Valkey 服务器的扩展)。每个运行脚本的应用程序实例都必须随时准备好脚本的源代码以供加载。这是因为脚本仅由服务器缓存且是易失的。随着应用程序的增长,这种方法在开发和维护方面可能会变得更加困难。
其次,Valkey 函数在 v7.0 中添加,它们本质上是作为一流数据库元素的脚本。因此,函数将脚本与应用程序逻辑解耦,并支持脚本的独立开发、测试和部署。要使用函数,它们需要首先被加载,然后才能供所有连接的客户端使用。在这种情况下,将函数加载到数据库成为一项管理部署任务(例如,加载一个 Valkey 模块),从而将脚本与应用程序分离。
请参阅以下页面以获取更多信息
运行脚本或函数时,Valkey 保证其原子执行。脚本的执行在其整个过程中会阻塞所有服务器活动,类似于事务的语义。这些语义意味着脚本的所有效果要么尚未发生,要么已经发生。已执行脚本的阻塞语义始终适用于所有连接的客户端。
请注意,这种阻塞方法的潜在缺点是执行慢速脚本不是一个好主意。创建快速脚本并不难,因为脚本的开销非常低。但是,如果您打算在应用程序中使用慢速脚本,请注意,当它运行时,所有其他客户端都会被阻塞,并且无法执行任何命令。
只读脚本
只读脚本是仅执行不修改 Valkey 中任何键的命令的脚本。只读脚本可以通过向脚本添加 no-writes
标志来执行,或者通过使用只读脚本命令变体之一:EVAL_RO
、EVALSHA_RO
或 FCALL_RO
来执行。它们具有以下特性:
- 它们始终可以在副本上执行。
- 它们始终可以通过
SCRIPT KILL
命令终止。 - 当 Valkey 超过内存限制时,它们永远不会因 OOM(内存不足)错误而失败。
- 它们在写入暂停期间不会被阻塞,例如在协调故障转移期间发生的暂停。
- 它们不能执行任何可能修改数据集的命令。
- 目前,
PUBLISH
、SPUBLISH
和PFCOUNT
在脚本中也被视为写入命令,因为它们可能会尝试将命令传播到副本和 AOF 文件。
除了所有只读脚本提供的优点外,只读脚本命令还具有以下优势:
- 它们可以用于配置 ACL 用户,使其只能执行只读脚本。
- 许多客户端也更好地支持将只读脚本命令路由到副本,适用于希望使用副本进行读扩展的应用程序。
只读脚本历史
只读脚本和只读脚本命令是在 Redis OSS 7.0 中引入的。
- 在 Redis OSS 7.0.1 之前,
PUBLISH
、SPUBLISH
和PFCOUNT
在脚本中不被视为写入命令。 - 在 Redis OSS 7.0.1 之前,
no-writes
标志并不意味着allow-oom
。 - 在 Redis OSS 7.0.1 之前,
no-writes
标志不允许脚本在写入暂停期间运行。
建议的方法是使用带有 no-writes
标志的标准脚本命令,除非您需要前面提到的功能之一。
沙盒脚本上下文
Valkey 将执行用户脚本的引擎置于沙盒中。沙盒旨在防止意外误用并减少来自服务器环境的潜在威胁。
脚本绝不应尝试访问 Valkey 服务器底层的主机系统,例如文件系统、网络,或尝试执行 API 支持的系统调用之外的任何其他系统调用。
脚本应仅对存储在 Valkey 中的数据以及作为执行参数提供的数据进行操作。
最大执行时间
脚本受最大执行时间(默认为五秒)的限制。这个默认超时时间非常长,因为脚本通常在不到一毫秒内运行。此限制旨在处理开发过程中意外创建的无限循环。
可以通过 valkey.conf
或使用 CONFIG SET
命令以毫秒精度修改脚本的最大执行时间。影响最大执行时间的配置参数名为 busy-reply-threshold
。
当脚本达到超时阈值时,Valkey 不会自动终止它。这样做会违反 Valkey 与脚本引擎之间的约定,该约定确保脚本是原子的。中断脚本的执行可能会导致数据集留下半写入的更改。
因此,当脚本执行时间超过配置的超时时间时,会发生以下情况:
- Valkey 会记录脚本运行时间过长。
- 它会再次接受来自其他客户端的命令,但会向所有发送常规命令的客户端回复 BUSY 错误。在此状态下唯一允许的命令是
SCRIPT KILL
、FUNCTION KILL
和SHUTDOWN NOSAVE
。 - 可以使用
SCRIPT KILL
和FUNCTION KILL
命令终止仅执行只读命令的脚本。这些命令不会违反脚本语义,因为脚本尚未向数据集写入任何数据。 - 如果脚本已经执行了哪怕一次写入操作,唯一允许的命令是
SHUTDOWN NOSAVE
,它会在不将当前数据集保存到磁盘的情况下停止服务器(基本上,服务器被中止)。