Redis 发布/订阅

如何在 Redis 中使用发布/订阅频道

SUBSCRIBEUNSUBSCRIBE实现发布/订阅消息传递范式PUBLISH,其中(引用维基百科)发送者(发布者)没有被编程为将消息发送给特定接收者(订阅者)。相反,发布的消息被划分为多个频道,而不知道可能有哪些订阅者(如果有的话)。订阅者对一个或多个频道表示兴趣,并且只接收感兴趣的消息,而不知道有哪些发布者(如果有的话)。发布者和订阅者的这种分离允许更大的可扩展性和更动态的网络拓扑。

例如,为了订阅频道“channel11”和“ch:00”,客户端发出SUBSCRIBE提供频道名称的命令:

SUBSCRIBE channel11 ch:00

其他客户端发送到这些频道的消息将被 Redis 推送给所有订阅的客户端。订阅者按照消息发布的顺序接收消息。

订阅了一个或多个频道的客户端不应发出命令,但它可以向其他频道发送命令SUBSCRIBEUNSUBSCRIBE从其他频道发送命令。对订阅和取消订阅操作的回复以消息的形式发送,因此客户端只需读取连贯的消息流,其中第一个元素表示消息的类型。在订阅的 RESP2 客户端上下文中允许的命令包括:

但是,如果使用 RESP3(参见HELLO),客户端可以在订阅状态下发出任何命令。

请注意,使用时,在订阅模式下不能使用redis-cli诸如UNSUBSCRIBE和之类的命令,因为不会接受任何命令,只能使用退出模式。PUNSUBSCRIBEredis-cliCtrl-C

传递语义

Redis 的 Pub/Sub 展现了最多一次消息传递语义。顾名思义,这意味着一条消息最多只传递一次。一旦 Redis 服务器发送了该消息,就不可能再次发送。如果订阅者无法处理该消息(例如,由于错误或网络断开),该消息将永远丢失。

如果您的应用程序需要更强的交付保证,您可能需要了解Redis Streams。流中的消息是持久化的,并且支持最多一次至少一次交付语义。

推送消息格式

一条消息是一个包含三个元素的数组回复

第一个元素是消息的类型:

  • subscribe:表示我们成功订阅了回复中第二个元素给出的频道。第三个参数表示我们当前订阅的频道数量。

  • unsubscribe:表示我们已成功取消订阅回复中第二个元素给出的频道。第三个参数表示我们当前订阅的频道数。当最后一个参数为零时,我们不再订阅任何频道,并且客户端可以发出任何类型的 Redis 命令,因为我们处于 Pub/Sub 状态之外。

  • message:它是另一个客户端发出的命令的结果而收到的消息PUBLISH。第二个元素是原始通道的名称,第三个参数是实际的消息负载。

数据库和范围

Pub/Sub 与密钥空间无关。它不会在任何层面上干扰密钥空间,包括数据库编号。

在数据库 10 上发布的内容将被数据库 1 上的订阅者听到。

如果您需要某种类型的范围界定,请在渠道前面加上环境名称(测试、暂存、生产……)。

有线协议示例

SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2

此时,我们从另一个客户端PUBLISH针对名为的通道发出一个操作second

> PUBLISH second Hello

这是第一个客户收到的内容:

*3
$7
message
$6
second
$5
Hello

UNSUBSCRIBE现在客户端使用不带附加参数的命令取消订阅所有频道:

UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0

模式匹配订阅

Redis Pub/Sub 实现支持模式匹配。客户端可以订阅 glob 样式的模式,以接收发送到与给定模式匹配的频道名称的所有消息。

例如:

PSUBSCRIBE news.*

将接收发送到频道、等的所有消息news.art.figurativenews.music.jazz所有 glob 样式模式均有效,因此支持多个通配符。

PUNSUBSCRIBE news.*

然后将取消客户端对该模式的订阅。此调用不会影响其他订阅。

通过模式匹配收到的消息以不同的格式发送:

  • 消息的类型为pmessage:它是另一个客户端发出的命令的结果PUBLISH,与模式匹配订阅匹配。第二个元素是匹配的原始模式,第三个元素是原始通道的名称,最后一个元素是实际的消息负载。

SUBSCRIBE和类似UNSUBSCRIBE,系统会通过发送类型为 的消息来确认PSUBSCRIBE和命令,并使用与和消息格式相同的格式。PUNSUBSCRIBEpsubscribepunsubscribesubscribeunsubscribe

与模式和频道订阅匹配的消息

如果客户端订阅了与已发布消息匹配的多个模式,或者订阅了与该消息匹配的模式和频道,则客户端可能会多次收到一条消息。以下示例显示了这一点:

SUBSCRIBE foo
PSUBSCRIBE f*

在上面的例子中,如果向 channel 发送一条消息foo,则客户端将收到两条消息:一条为类型message,另一条为类型pmessage

模式匹配的订阅计数含义

subscribeunsubscribepsubscribe消息punsubscribe类型中,最后一个参数是仍处于活动状态的订阅数。此数字是客户端仍订阅的频道和模式的总数。因此,仅当由于取消订阅所有频道和模式而导致此计数降至零时,客户端才会退出 Pub/Sub 状态。

分片发布/订阅

从 Redis 7.0 开始,引入了分片发布/订阅,其中分片通道通过与将键分配给槽相同的算法分配给槽。必须将分片消息发送到拥有分片通道哈希到的槽的节点。集群确保已发布的分片消息转发到分片中的所有节点,因此客户端可以通过连接到负责该槽的主服务器或其任何副本来订阅分片通道。 SSUBSCRIBESUNSUBSCRIBESPUBLISH用于实现分片发布/订阅。

分片发布/订阅有助于在集群模式下扩展发布/订阅的使用。它将消息的传播限制在集群的分片内。因此,与全局发布/订阅相比,通过集群总线的数据量是有限的,全局发布/订阅中每条消息都会传播到集群中的每个节点。这允许用户通过添加更多分片来水平扩展发布/订阅的使用。

编程示例

Pieter Noordhuis 提供了一个很好的示例,使用 EventMachine 和 Redis 创建多用户高性能网络聊天

客户端库实现提示

由于所有收到的消息都包含导致消息传递的原始订阅(对于消息类型,则为通道;对于 pmessage 类型,则为原始模式),因此客户端库可以使用哈希表将原始订阅绑定到回调(可以是匿名函数、块、函数指针)。

当收到消息时,可以进行 O(1)查找以将消息传递给已注册的回调。

给此页面评分
返回顶部 ↑