目录
1.什么是发布订阅
1.1概念
1.2发布订阅过程
1.3发布订阅分为两类
2. 频道的订阅与退订
2.1subcribe
2.2退订频道
3. 模式的订阅和退订
3.1模式的订阅
3.2punsubscribe
4.频道和模式的发布
4.1频道的发布
4.2模式的发布
1.什么是发布订阅
1.1概念
1.发布订阅模式又叫观察者模式,是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
2.主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似。
3.由三部分组成:发布者(pub),订阅者(sub)和频道(channel)
4.Redis 客户端可以订阅任意数量的频道。
5.Redis 在订阅者和发布者之间起到了消息路由的功能。
1.2发布订阅过程
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端
1.3发布订阅分为两类
1.频道的发布订阅
2.模式的发布订阅
2. 频道的订阅与退订
2.1subcribe
当一个客户端执行SUBSCRIBE命令订阅某个或某些频道的时候, 这个客户端与被订阅频道之间就建立起了一种订阅关系
格式 SUBSCRIBE channel [channel …]
底层原理 :
1.pubsub_channels字典
Redis将所有频道的订阅关系都保存在服务器状态
struct redisServer {
// ...
//
保存所有频道的订阅关系
dict *pubsub_channels;
// ...
};
图形示意:
client-1、client-2、client-3三个客户端正在订阅"news.it"频道。
·客户端client-4正在订阅"news.sport"频道。
·client-5和client-6两个客户端正在订阅"news.business"频道。
2.情况分类
1.如果频道已经有其他订阅者,那么它在pubsub_channels字典中必 然有相应的订阅者链表,程序唯一要做的就是将客户端添加到订阅者链 表的末尾。
2·如果频道还未有任何订阅者,那么它必然不存在于 pubsub_channels字典,程序首先要在pubsub_channels字典中为频道创建 一个键,并将这个键的值设置为空链表,然后再将客户端添加到链表, 成为链表的第一个元素
图形示意
SUBSCRIBE "news.sport" "news.movie”
1. ·更新后的pubsub_channels字典新增了"news.movie"键,该键对应的 链表值只包含一个client-10086节点,表示目前只有client-10086一个客户 端在订阅"news.movie"频道
2.至于原本就已经有客户端在订阅的"news.sport"频道,client-10086 的节点放在了频道对应链表的末尾
2.2退订频道
格式 unsub channel message
底层原理:
UNSUBSCRIBE命令的行为和SUBSCRIBE命令的行为正好相反, 当一个客户端退订某个或某些频道的时候,服务器将从pubsub_channels 中解除客户端与被退订频道之间的关联
图形示意:
·程序会根据被退订频道的名字,在pubsub_channels字典中找到频 道对应的订阅者链表,然后从订阅者链表中删除退订客户端的信息。
·如果删除退订客户端之后,频道的订阅者链表变成了空链表,那 么说明这个频道已经没有任何订阅者了,程序将从pubsub_channels字典 中删除频道对应的键
执行之后
UNSUBSCRIBE "news.sport" "news.movie"
3. 模式的订阅和退订
3.1模式的订阅
1.psubscribe命令
-
格式: PSUBSCRIBE pattern [pattern …]
-
eg : PSUBSCRIBE China* 订阅以China为开头的所有频道
-
底层原理
-
1.redisServer.pubsub_patterns 属性是一个链表,链表中保存着所有和模式相关的信息:
2.链表中的每个节点都包含一个 redis.h/pubsubPattern 结构:
3.client 属性保存着订阅模式的客户端,而 pattern 属性则保存着被订阅的模式。
4.每当调用 PSUBSCRIBE 命令订阅一个模式时,程序就创建一个包含客户端信息和被订阅模式的 pubsubPattern 结构,并将该结构添加到redisServer.pubsub_patterns 链表中
举个例子,下图展示了一个包含两个模式的 pubsub_patterns 链表, 其中 client123 和 client256 都正在订阅 tweet.shop.* 模式
-
如果这时客户端
client10086
执行PSUBSCRIBE broadcast.list.*
, 么pubsub_patterns
链表将被更新成这样:
note1
假设客户端同时订阅了某种模式和符合该模式的某个频道,那么发送给这个频道的消息将被客户端接收到两次,只不过这两条消息的类型不同,一个是message类型,一个是pmessage类型,但其内容相同
3.2punsubscribe
格式: PUNSUBSCRIBE [pattern [pattern …]]
原理:这个命令执行的是订阅模式的反操作:程序会删除redisServer.pubsub_patterns 链表中,所有和被退订模式相关联的 pubsubPattern 结构,这样客户端就不会再收到和模式相匹配的频道发来的信息。
note1 1.在SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE和PUNSUBSCRIBE命令中,其返回值都包含了该客户端当前订阅的频道和模式的数量,当这个数量变为0时,该客户端会自动退出订阅状态。
2.PUBLISH和SUBSCRIBE的缺陷在于客户端必须一直在线才能接收到消息,断线可能会导致客户端丢失消息,除此之外,旧版的redis可能会由于订阅者消费不够快而变的不稳定导致崩溃,甚至被管理员杀掉
4.频道和模式的发布
4.1频道的发布
命令 PUSHLISH<channel><message>
因为服务器状态中的pubsub_channels字典记录了所有频道的订阅关 系,所以为了将消息发送给channel频道的所有订阅者,PUBLISH命令 要做的就是在pubsub_channels字典里找到频道channel的订阅者名单(一 个链表),然后将消息发送给名单上的所有客户端
例子1
PUBLISH "news.it" "hello"
那么PUBLISH命令将在pubsub_channels字典中查找键"news.it"对应 的链表值,并通过遍历链表将消息"hello"发送给"news.it"频道的三个订 阅者:client-1、client-2和client-3。
4.2模式的发布
发送信息到模式的工作也是由 PUBLISH 命令进行的。PUBLISH 除了将 message 发送到所有订阅 channel 的客户端之外,它还会将 channel 和 pubsub_patterns 中的模式进行对比,如果 channel 和某个模式匹配的话,那么也将 message 发送到订阅那个模式的客户端
eg.下图展示了一个带有频道和模式的例子, 其中 tweet.shop.*
模式匹配了tweet.shop.kindle
频道和 tweet.shop.ipad
频道, 并且有不同的客户端分别订阅它们三个
当有信息发送到 tweet.shop.kindle
频道时, 信息除了发送给 clientX
和 clientY
之外, 还会发送给订阅 tweet.shop.*
模式的 client123
和 client256