redis pub/sub

SUBSCRIBE,UNSUBSCRIBE和PUBLISH实现发布/订阅消息传递范例,其中(引用维基百科)发件人(发布者)未被编程为将其消息发送给特定接收者(订阅者)。 相反,发布的消息被表征为信道,而不知道可能存在什么(如果有的话)订户。 订阅者表达对一个或多个频道的兴趣,并且仅接收感兴趣的消息,而不知道存在哪些(如果有的话)发布者。 发布者和订阅者的这种分离可以实现更大的可扩展性和更动态的网络拓扑。

例如,为了订阅频道foo和bar,客户端发出SUBSCRIBE,提供频道名称:

1
SUBSCRIBE foo bar

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

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

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

推送消息的格式

消息是具有三个元素的Array回复。

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

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

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

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

数据库和范围

Pub / Sub与key空间无关。 它被认为不会在任何级别上干扰它,包括数据库号。

数据库1上的订阅者将听到db 10上的发布。

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

有线协议示例

1
2
3
4
5
6
7
8
9
10
11
12
13
SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2

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

1
> PUBLISH second Hello

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

1
2
3
4
5
6
7
*3
$7
message
$6
second
$5
Hello

现在,客户端使用UNSUBSCRIBE命令从所有通道取消订阅,而无需其他参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0

模式匹配订阅

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

例如:

1
PSUBSCRIBE news.*

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

1
PUNSUBSCRIBE news.*

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

由于模式匹配而收到的消息以不同的格式发送:

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

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

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

如果客户端订阅了与已发布消息匹配的多个模式,或者如果订阅了与该消息匹配的模式和信道,则客户端可以多次接收单个消息。 如下例所示:

1
2
SUBSCRIBE foo
PSUBSCRIBE f*

在上面的示例中,如果将消息发送到通道foo,则客户端将收到两条消息:一个是message消息,一个是pmessage。

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

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

编程示例

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

客户端库实现提示

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

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