dot Redis 8 已发布——它是开源的

了解更多

触发器和函数:让代码更贴近数据

开发者可以使用 Redis 构建和维护实时应用。您可以在 Redis 数据库中直接创建 JavaScript 函数,使其在数据变化时自动执行代码,从而确保更低的延迟。

通常,应用程序处理业务逻辑操作,并将代码发送到数据库执行。这是一个缓慢的过程,因为每次执行函数时,代码都从客户端流向服务器。开发者负责维护访问同一数据库的所有应用程序之间的代码一致性,无论是简单的请求还是复杂的数据操作,而且很多时候代码会在不同应用程序之间重复。

遵循 Redis 的宣言指南“我们反对复杂性”,我们必须采取行动来寻找解决这些挑战的方法。

四年前,我们引入了 RedisGears,这是我们在平台内的第一个可编程模型。 开发者在数据所在之处编写和执行脚本。然而,这些脚本是临时的,由每个客户端提供,这可能导致不一致。

沿着这个方向,在 Redis 7.0 中,我们引入了使用 functions 的脚本方法的初步实现。函数提高了可用性和持久性,因为它们是数据库的一部分,继承了数据的复制和持久化级别。

现在,我们很荣幸推出可编程性的下一步。在 Redis 7.2 中,我们引入了触发器和函数。它们增强了 Redis 的可编程性,扩展了服务器端能力,改进了函数在数据库中执行的方式和时机,并促进了复杂业务逻辑直接在数据所在之处执行。

触发器和函数的基础知识

触发器和函数是通过 Redis Stack 提供的新一代可编程性。它允许开发者直接在 Redis 数据库中编写、存储 JavaScript 代码,并在数据变化时自动执行。

这项能力使开发者能够定义事件(称为触发器),以在更靠近数据的地方执行函数。也就是说,开发者定义业务逻辑,使其响应数据库事件或命令而执行。这加快了代码和相关交互的速度,因为无需等待将代码从客户端带入数据库。

它还加快了对 Redis 中其他事件的反应时间,例如键空间通知,这些通知通过其他方式(例如发布和订阅 (Pub/Sub) 事件)无法实时处理。

触发器和函数处理集群数据库中的分发,在每个分片上安装库,并根据键所在位置执行函数。

我们还引入了远程函数。远程函数允许您执行可以访问任何槽位数据的读取操作,即使在集群数据库中也是如此,因此您的所有数据都可以从每个函数中访问。

它使用 JavaScript,最流行的编程语言

Redis 使用 Lua 进行脚本编写和函数开发。Lua 有许多优点,例如代码可重用性,但它在专业开发者中并不是一种常用语言。根据2022 年 StackOverflow 开发者调查,只有 3.2% 的开发者在专业领域使用 Lua。

相比之下,三分之二的开发者使用 JavaScript。使用一种常用语言降低了新 Redis 开发者的入门门槛。这少学一样东西。

应用代码更容易支持和维护

触发器和函数的另一个好处是它降低了跨多个应用程序管理业务逻辑的复杂性。

当多个应用程序访问同一个数据库时,开发者必须协调应用程序如何以一致的方式处理数据。通常需要在每个应用程序中复制代码来验证数据、丰富搜索结果,或在另一个应用程序进行更改时更新数据库。

使用触发器和函数,不再需要在多个应用程序上复制代码。代码始终以相同的方式执行,无论是按需执行还是由数据库中的事件触发。

数据库事件实时处理

到目前为止,在 Redis 中响应数据库事件需要开发者依赖 Pub/Sub 机制。虽然 Pub/Sub 有很多优点,但它并非总是正确的选择。特别是,Pub/Sub 不是实时的。客户端必须主动监听事件;如果客户端未监听,事件就会丢失。

现在,开发者可以注册基于键前缀和事件类型执行的键空间触发器。触发器可以以原子方式执行,以便在事件和业务逻辑之间不会处理其他 Redis 事件。

告诉我如何实现

通过实际示例来理解事物总是更容易。这里,我们介绍如何注册函数和触发器。函数在通过 TFCALL 命令调用时执行;触发器基于 Redis 中的事件执行。

序言定义了我们使用 js 引擎,库名称为 lib,并且所需的最低触发器和函数 API 版本为 1.0。

#!js name=lib api_version=1.0

接下来,我们创建一个函数,该函数返回 Redis 命令的结果。客户端提供了在我们函数内部执行 Redis 命令的权限。数据事件包含在运行函数时可以提供的键和参数。

function answer(client, data) {
	return client.call(“ping”);
}

Redis 全局变量允许您注册触发器和函数,并记录到日志文件。我们注册函数时指定一个名称,以便在执行时调用它。

redis.registerFunction(‘playPingPong’, answer);

完整的 JavaScript 文件如下所示。

#!js name=lib api_version=1.0

function answer(client, data) {
	return client.call(‘ping’);
}

redis.registerFunction(‘playPingPong’, answer);

将此保存为 lib.js

然后我们使用 TFUNCTION LOAD 命令在触发器和函数中注册我们的函数。TFUNCTION LOAD 命令还会在集群数据库中分发库。

> redis-cli  -x TFUNCTION LOAD < ./lib.js
OK

现在我们可以使用 TFCALL 命令执行函数。该命令获取库名称和函数名称,两者之间用点号分隔。

>redis-cli TFCALL lib.playPingPong 0
“PONG”

通过这样做,您成功地在 Redis 数据库中创建、注册和触发了一个函数。

我们可以使用键空间触发器扩展此示例。我们添加一个新的注册,该注册会响应以 'fellowship:' 为前缀的键。将此代码添加到 lib.js 文件的末尾。

function addLastUpdatedField(client, data) {
	if(data.event == ‘hset’) {
	var currentDateTime = Date.now();
	client.call(‘hset’, data.key, ‘last_updated’, currentDateTime.toString());
}
}

redis.registerKeySpaceTrigger(‘addLastUpdated’, 'fellowship:', addLastUpdatedField);

使用带有 REPLACE 参数的 TFUNCTION LOAD 命令来更新现有库。TFUNCTION LOAD REPLACE 命令会立即更新所有使用 Redis 数据库的客户端,并且它们开始使用新的业务逻辑。

>redis-cli -x TFUNCTION LOAD REPLACE . < ./lib.js
OK

要测试新的键空间触发器,创建一个以 fellowship: 开头的新键,并使用 RedisInsight 检查字段。键空间触发器会随着命令一起执行,因此在创建键时就已经添加了 last_updated 字段。

Check the results in RedisInsight
在 RedisInsight 中检查结果

听起来不错?亲身体验一下吧

参与 Redis Stack 7.2 触发器和函数的公开预览。通过在 Google Cloud/亚太地区 (东京) 或 AWS/亚太地区 (新加坡) 区域的固定层中,在 Redis Enterprise Cloud 上创建一个数据库,或者从我们的下载中心部署一个自管理实例,开始在云端使用 Redis Stack。

触发器和函数的正式发布计划在 Redis 8 中。这将包括从预览用户那里收到的反馈,以及更多附加功能,例如定时触发器和更多调试选项。

欢迎在Redis 邮件列表上提供评论和反馈。