一.订阅与发布

Redis 通过 PUBLISHSUBSCRIBE 等命令实现了订阅与发布模式, 这个功能提供两种信息机制, 分别是订阅/发布到频道和订阅/发布到模式, 下文先讨论订阅/发布到频道的实现, 再讨论订阅/发布到模式的实现。下面是应用场景,先直观的了解下。

1、实时消息系统!
2、实时聊天!(频道当做聊天室,将信息回显给所有人即可!)
3、订阅,关注系统都!

二.频道的订阅与信息发送

Redis 的  SUBSCRIBE 命令可以让客户端订阅任意数量的频道, 每当有新信息发送到被订阅的频道时, 信息就会被发送给所有订阅指定频道的客户端。

作为例子, 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

二十四、redis发布订阅

 

当有新消息通过 PUBLISH命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

二十四、redis发布订阅

 

在后面的内容中, 我们将探讨 SUBSCRIBE 和 PUBLISH  命令的实现, 以及这套订阅与发布机制的运作原理。

三.订阅频道

每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构, 结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息。

其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表链表中保存了所有订阅这个频道的客户端

比如说,在下图展示的这个 pubsub_channels 示例中, client2 、 client5 和 client1 就订阅了 channel1 , 而其他频道也分别被别的客户端所订阅:

二十四、redis发布订阅

 

当客户端调用 SUBSCRIBE 命令时, 程序就将客户端和要订阅的频道在 pubsub_channels 字典中关联起来。

举个例子,如果客户端 client10086 执行命令 SUBSCRIBE channel1 channel2 channel3 ,那么前面展示的 pubsub_channels 将变成下面这个样子:

二十四、redis发布订阅

通过 pubsub_channels 字典, 程序只要检查某个频道是否为字典的键, 就可以知道该频道是否正在被客户端订阅; 只要取出某个键的值, 就可以得到所有订阅该频道的客户端的信息。

四.发送信息到频道

了解了 pubsub_channels 字典的结构之后, 解释  PUBLISH 命令的实现就非常简单了: 当调用 PUBLISH channel message 命令, 程序首先根据 channel 定位到字典的键, 然后将信息发送给字典值链表中的所有客户端。

比如说,对于以下这个 pubsub_channels 实例, 如果某个客户端执行命令 PUBLISH channel1 "hello moto" ,那么 client2 、 client5 和 client1 三个客户端都将接收到 "hello moto" 信息:

二十四、redis发布订阅

 

五.退订频道

使用 UNSUBSCRIBE 命令可以退订指定的频道, 这个命令执行的是订阅的反操作: 它从 pubsub_channels 字典的给定频道(键)中, 删除关于当前客户端的信息, 这样被退订频道的信息就不会再发送给这个客户端。

六.模式的订阅与信息发送

当使用 PUBLISH 命令发送信息到某个频道时, 不仅所有订阅该频道的客户端会收到信息, 如果有某个/某些模式和这个频道匹配的话, 那么所有订阅这个/这些频道的客户端也同样会收到信息。

下图展示了一个带有频道和模式的例子, 其中 tweet.shop.* 模式匹配了 tweet.shop.kindle 频道和 tweet.shop.ipad 频道, 并且有不同的客户端分别订阅它们三个:

二十四、redis发布订阅

当有信息发送到 tweet.shop.kindle 频道时, 信息除了发送给 clientX 和 clientY 之外, 还会发送给订阅 tweet.shop.* 模式的 client123 和 client256 :

二十四、redis发布订阅

另一方面, 如果接收到信息的是频道 tweet.shop.ipad , 那么 client123 和 client256 同样会收到信息:

二十四、redis发布订阅

七.测试

订阅端:
Redis是使用C实现的,通过分析 Redis 源码里的 pubsub.c 文件,了解发布和订阅机制的底层实现,借此加深对 Redis 的理解。
127.0.0.1:6379> SUBSCRIBE sj # 订阅一个频道 sj
二十四、redis发布订阅
# 等待读取推送的信息,另外开启一个窗口作为发送端

二十四、redis发布订阅
1) "message" # 消息
2) "sj" # 那个频道的消息
3) "hello,kuangshen" # 消息的具体内容

二十四、redis发布订阅
1) "message"
2) "kuangshenshuo"
3) "hello,redis"

发送端:

127.0.0.1:6379> PUBLISH sj "hello,sj" # 发布者发布消息到频道!
二十四、redis发布订阅
127.0.0.1:6379> PUBLISH sj "hello,redis" # 发布者发布消息到频道!
二十四、redis发布订阅

 

相关文章: