阅读 41

Redis Pub/Sub

SUBSCRIBE,UNSUBSCRIBE和PUBLISH实现发布-订阅模式的消息传递范例,其中(引用Wikipedia)发送者(发布者)没有被编程为将其消息发送到特定的接收者(订阅者)。相反,发布的消息被描述成频道,而不知道(如果有的话)订阅者可能是谁。订阅者对一个或多个渠道表示兴趣,并且仅接收感兴趣的消息,而不知道那里有哪些发布者。发布者和订阅者之间的这种解耦可以实现更大的可伸缩性和更动态的网络拓扑。

例如,为了订阅通道foo和bar,客户端发出一个订阅,提供通道的名称

SUBSCRIBE foo bar
复制代码

其他客户端发送到这些通道的消息将由Redis推送到所有订阅的客户端。

订阅一个或多个频道的客户端不应发出命令,尽管它可以订阅其他频道或从其他频道取消订阅。对订阅和取消订阅操作的答复以消息的形式发送,以便客户端可以读取连贯的消息流,其中第一个元素表示消息的类型。在已订阅客户端的上下文中允许使用的命令是SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE,PUNSUBSCRIBE,PING和QUIT。

请注意,redis-cli一旦在订阅模式下将不接受任何命令,并且只能使用Ctrl-C退出该模式。

推送消息的格式

消息是具有三个元素的数组回复。 第一个元素是消息的类型:

  • subscribe:表示我们成功订阅了作为应答中的第二个元素给出的通道。第三个参数表示我们当前订阅的频道的数量。
  • unsubscribe:意味着我们成功地取消了作为响应中第二个元素的通道的订阅。第三个参数表示我们当前订阅的频道的数量。当最后一个参数为零时,我们将不再订阅任何频道,并且由于我们不在发布/订阅状态,因此客户端可以发出任何类型的Redis命令。
  • message:它是由于另一个客户端发出的PUBLISH命令而收到的消息。第二个元素是原始通道的名称,第三个参数是实际的消息有效负载。

数据库和作用域

发布/订阅与key空间无关。使其在任何级别(包括数据库编号)都不会受到干扰。

在db 10上发布时,db 1上的订阅者将听到。

如果您需要某种范围,请在通道前面加上环境名称(测试,暂存,生产等)。

Wire protocol example

SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2
复制代码

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

> 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:它是作为另一个客户端发出的发布命令的结果接收的消息,该命令与模式匹配订阅相匹配。第二个元素是匹配的原始模式,第三个元素是原始通道的名称,最后一个元素是实际消息有效负载。

与SUBSCRIBE和UNSUBSCRIBE相似,系统会使用与订阅和取消订阅消息格式相同的格式发送psubscribe和punsubscribe类型的消息来确认PSUBSCRIBE和PUNSUBSCRIBE命令。

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

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

SUBSCRIBE foo
PSUBSCRIBE f*
复制代码

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

模式匹配的订阅计数的含义

在subscribe、unsubscribe、psubscribe和punsubscribe消息类型中,最后一个参数是仍处于活动状态的订阅计数。该数字实际上是客户端仍订阅的频道和模式的总数。因此,仅当由于取消订阅所有通道和模式而导致计数降至零时,客户端才会退出发布/订阅状态。

编程实例

Pieter Noordhuis提供了一个使用EventMachine和Redis创建多用户高性能Web聊天的好例子。

客户端库实施提示

因为所有接收到的消息包含原始订阅导致消息传递(通道的消息类型和原始模式pmessage类型)的客户端库可以将原来的订阅绑定到回调(块可以匿名函数,函数指针),使用一个哈希表。

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