Redis发布者/订阅者模式

相关命令

  • PSUBSCRIBE
  • PUBLISH
  • PUBSUB
  • PUNSUBSCRIBE
  • SUBSCRIBE
  • UNSUBSCRIBE

发布/订阅

SUBSCRIBE, UNSUBSCRIBE and PUBLISH实现了发布/订阅消息传递范式(引自维基百科),发送者(发布者)没有被编程为发送信息到特定的接受者(订阅者)。相反,发布消息被定义为通道,而不知道可能有哪些(如果有的话)订阅者。订阅者传递兴趣到一个或者更多的通道,并且仅接受感兴趣的消息,而不必知道发布者(如果有的话)是谁。发布者和订阅者的解耦可以实现更多的可伸缩性和更动态网络拓扑。

例如,为了订阅foobar,客户端发出了一个SUBSCRIBE并提供通道的名称。

SUBSCRIBE foo bar

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

一个客户端已经订阅一个或者多个通道后不应该再发送命令,尽管它可以订阅或者取消订阅其他通道。订阅和取消订阅操作以消息形式回复,因此客户端仅能阅读一个连贯的消息流,第一个元素指示消息的类型。订阅客户端可以使用的命令有:SUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, PUNSUBSCRIBE, PING 和 QUIT。

请注意,一旦处于订阅模式,redis-cli将不会接受任何命令,并且只能使用Ctrl-C来退出这个模式。

已发布消息的格式

一条消息是含有3个元素的数组回复.

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

  • subscribe:意味着我们成功的订阅了回复中第二个元素所代表的通道。第三个参数代表我们当前订阅的通道的数量。
  • unsubscribe:意味着我们成功的取消了回复中第二个参数所代表的通道的订阅。第三个参数代表我们当前订阅的通道的数量。当最后一个参数是0时,我们不再订阅任何通道,并且客户端可以发布任何类型的Redis命令,因为我们已经退出Pub/Sub状态了。
  • message:它代表的是接受一条由其他客户端发送的PUBLISH命令结果的消息。第二个元素是原始通道的名称,第三个参数代表的是实际的消息负载。

数据库 & 域

Pub/Sub跟键空间没有关联。它被设计为在任何层级上都不会被干扰,包括数据库号码。

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

如果你需要一些类型的域,使用环境的名称作为通道的前缀(test,staging,production,...)。

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-style)模式,以便接收名称与给定模式匹配的所有通道的所有消息。

例如:

PSUBSCRIBE news.*

将会接收到所有发送到news.art.figurative,news.music.jazz等通道上的消息。所有的全局风格(glob-style)模式都是有效的,所以多通配符是被支持的。

PUNSUBSCRIBE news.*

然后将所有客户端从该模式取消订阅。这次调用不会影响其他订阅。

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

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

与SUBSCRIBE 和 UNSUBSCRIBE相似, PSUBSCRIBE 和 PUNSUBSCRIBE 命令在系统发送psubscribepunsubscribe类型的消息时被确认,使用与subscribeunsubscribe相同的消息格式。

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

如果一个客户端订阅多个模式匹配到一条已发布的消息,或者它同时订阅模式和通道匹配该消息,那么它可能会多次接收一条消息。就像下面的例子:

SUBSCRIBE foo
PSUBSCRIBE f*

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

模式匹配的订阅意义

subscribe, unsubscribe, psubscribepunsubscribe消息类型中,最后一个参数是仍在活动中的订阅数量。这个数字实际上是客户端仍在订阅的通道和模式的总数。因此,仅当由于从通道和模式取消订阅导致这个数字降至0时,客户端才将会退出发布者/订阅者(Pub/Sub)状态。

编程示例

Pieter Noordhuis提供了一个非常棒的例子,使用EventMachine 和 Redis创建了一个多用户高性能web聊天室。

客户端库的实现提示

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

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

你可能感兴趣的:(Redis发布者/订阅者模式)