相关命令
发布/订阅
SUBSCRIBE, UNSUBSCRIBE and PUBLISH实现了发布/订阅消息传递范式(引自维基百科),发送者(发布者)没有被编程为发送信息到特定的接受者(订阅者)。相反,发布消息被定义为通道,而不知道可能有哪些(如果有的话)订阅者。订阅者传递兴趣到一个或者更多的通道,并且仅接受感兴趣的消息,而不必知道发布者(如果有的话)是谁。发布者和订阅者的解耦可以实现更多的可伸缩性和更动态网络拓扑。
例如,为了订阅foo
和bar
,客户端发出了一个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 命令在系统发送psubscribe
和punsubscribe
类型的消息时被确认,使用与subscribe
和unsubscribe
相同的消息格式。
同时匹配模式和通道的消息订阅
如果一个客户端订阅多个模式匹配到一条已发布的消息,或者它同时订阅模式和通道匹配该消息,那么它可能会多次接收一条消息。就像下面的例子:
SUBSCRIBE foo
PSUBSCRIBE f*
在上面的例子中,如果一条消息被发送到通道foo
,客户端将会接收到两个消息:一个是message
类型,另一个是pmessage
类型。
模式匹配的订阅意义
在subscribe
, unsubscribe
, psubscribe
和 punsubscribe
消息类型中,最后一个参数是仍在活动中的订阅数量。这个数字实际上是客户端仍在订阅的通道和模式的总数。因此,仅当由于从通道和模式取消订阅导致这个数字降至0时,客户端才将会退出发布者/订阅者(Pub/Sub)状态。
编程示例
Pieter Noordhuis提供了一个非常棒的例子,使用EventMachine 和 Redis创建了一个多用户高性能web聊天室。
客户端库的实现提示
因为接受的所有消息都包含原始的订阅信息,导致消息传递给(消息类型的通道,pmessage类型的原始模式)客户端类库需要绑定原始的订阅来回调(可以是匿名函数,块,函数指针),使用哈希表。
当接收到消息可以执行O(1)时间复杂度的查找,以便将消息传递给注册的回调。