首页 > 代码库 > Redis研究(十六)—发布/订阅模式

Redis研究(十六)—发布/订阅模式

        在上一篇中我们写了Redis的任务队列。

        除了实现任务队列外,Redis还提供了一组命令可以让开发者实现“发布/订阅”(publish/subscribe)模式。“发布/订阅”模式同样可以实现进程间的消息传递,其原理是这样的:

        “发布/订阅”模式中包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。
        发布者发布消息的命令是PUBLISH,用法是PUBLISH channel  message,如向channel.1说一声“hi”:
redis><span style="font-size:14px;">PUBLISH channel</span>.1 hi
(integer) 0


        这样消息就发出去了。PUBLISH命令的返回值表示接收到这条消息的订阅者数量。因为此时没有客户端订阅channel.1,所以返回0。发出去的消息不会被持久化,也就是说当有客户端订阅channel.1后只能收到后续发布到该频道的消息,之前发送的就收不到了。


        订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel [channel…]。现在新开一个redis-cli实例A,用它来订阅channel.1:

redis A>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe "
2) "channel.1"
3) (integer) 1

       执行SUBSCRIBE命令后客户端会进入订阅状态,处于此状态下客户端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE这4个属于“发布/订阅”模式的命令之外的命令(后面3个命令会在下面介绍),否则会报错。


       进入订阅状态后客户端可能收到三种类型的回复。每种类型的回复都包含3个值,第一个值是消息的类型,根据消息类型的不同,第二、三个值的含义也不同。消息类型可能的取值有:
(1)Subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个值是当前客户端订阅的频道数量。
(2)message。这个类型的回复是我们最关心的,它表示接收到的消息。第二个值表示产生消息的频道名称,第三个值是消息的内容。

(3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非“发布/订阅”模式的命令了。


      上例中当实例A订阅了channel.1进入订阅状态后收到了一条subscribe类型的回复,这时我们打开另一个redis-cli实例B,并向channel.1发送一条消息:
redis B>PUBLISH channel.1  hi!
(integer) 1

       返回值为1表示有一个客户端订阅了channel.1,此时实例A 收到了类型为message的回复:

1) "message "
2) "channel.1"
3) "hi!"

      使用UNSUBSCRIBE命令可以取消订阅指定的频道,用法为UNSUBSCRIBE[channel [channel  …]],如果不指定频道则会取消订阅所有频道。


按照规则订阅


      除了可以使用SUBSCRIBE命令订阅指定名称的频道外,还可以使用PSUBSCRIBE命令订阅指定的规则。规则支持glob风格通配符格式,下面我们新打开一个redis-cli实例C进行演示:
redis C>PSUBSCRIBE channel.?*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe "
2) "channel.?*"
3) (integer) 1

      规则channel.?*可以匹配channel.1和channel.10,但不会匹配channel.。这时在实例B中发布消息:
redis B>PUBLISH channel.1 hi!
(integer) 2

      返回结果为2是因为实例A和实例C两个客户端都订阅了channel.1频道。实例C接收到的回复是:
1) "pmessage "
2) "channel.?*"
3) "channel.1"
4) "hi!"

       第一个值表示这条消息是通过PSUBSCRIBE命令订阅频道而收到的,第二个值表示订阅时使用的通配符,第三个值表示实际收到消息的频道命令,第四个值则是消息内容。


      使用PSUBSCRIBE命令可以重复订阅一个频道,如某客户端执行了PSUBSCRIBE channel.? channel.?*,这时向channel.2发布消息后该客户端会收到两条消息,而同时PUBLISH命令返回的值也是2而不是1。同样的,如果有另一个客户端执行了SUBSCRIBE channel.10,和PSUBSCRIBE channel.?*的话,向channel.10发送命令该客户端也会收到两条消息( 但是是两种类型,message 和pmessage ) ,同时PUBLISH命令会返回2。


     PUNSUBSCRIBE命令可以退订指定的规则,用法是PUNSUBSCRIBE [pattern [pattern…]],如果没有参数则会退订所有规则。


     使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道; 同样UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则。另外容易出错的一点是使用PUNSUBSCRIBE命令退订某个规则时不会将其中的通配符展开,而是进行严格的字符串匹配,所以PUNSUBSCRIBE *无法退订channel.*规则,而是必须使用PUNSUBSCRIBE channel.*才能退订

Redis研究(十六)—发布/订阅模式