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