一,什么是发布订阅
-
概念
- 发布订阅模式又叫观察者模式,是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
- 主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似。
- 由三部分组成:发布者(pub),订阅者(sub)和频道(channel)
- Redis 客户端可以订阅任意数量的频道。
- Redis 在订阅者和发布者之间起到了消息路由的功能。
-
发布订阅过程
- 当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
- 当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
-
发布订阅分为两类
- 频道的发布订阅
- 模式的发布订阅
二,频道的发布订阅
-
subscribe 命令: 可以让客户端订阅任意数量的频道,每当有新信息发送到被订阅的频道时,信息就会被发送给所有订阅指定频道的客户端。
-
格式: SUBSCRIBE channel [channel …]
-
底层原理:
-
每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构,结构的 pubsub_channels 属性是一个字典{channel:[client1,client2…]},它的key为正在被订阅的频道,value为链表保存订阅该频道的客户端。这个字典就用于保存订阅频道的客户端;
-
通过
pubsub_channels
字典, 程序只要检查某个频道是否为pubsub_channels
字典的键, 就可以知道该频道是否正在被客户端订阅; 只要取出某个键的值, 就可以得到所有订阅该频道的客户端的信息。 -
其返回值包括客户端订阅的频道,目前已订阅的频道数量,以及接收到的消息,其中subscribe表示已经成功订阅了某个频道
-
-
-
publish 命令: 将信息发送到指定的频道
-
格式: PUBLISH channel message
-
底层原理:
- 当调用
PUBLISH channel message
命令, 程序首先根据channel
定位到字典的键, 然后将信息发送给字典值链表中的所有客户端。
- 当调用
-
-
unsubscribe 命令: 指退订给定的频道
- 格式: UNSUBSCRIBE [channel [channel …]]
- 底层原理:
- 这个命令执行的是订阅的反操作:它从 pubsub_channels 字典的给定频道(键)中,删除关于当前客户端的信息
- 由于Redis的订阅操作是阻塞式的这样被退订频道的信息就不会再发送给这个客户端。
三,模式的发布订阅
-
psubscribe 命令: 订阅一个或多个符合给定模式的频道
-
格式: PSUBSCRIBE pattern [pattern …]
-
eg : PSUBSCRIBE China* 订阅以China为开头的所有频道
-
底层原理:
-
redisServer.pubsub_patterns
属性是一个链表,链表中保存着所有和模式相关的信息: -
链表中的每个节点都包含一个
redis.h/pubsubPattern
结构: -
client
属性保存着订阅模式的客户端,而pattern
属性则保存着被订阅的模式。 -
每当调用 PSUBSCRIBE 命令订阅一个模式时,程序就创建一个包含客户端信息和被订阅模式的 pubsubPattern 结构,并将该结构添加到redisServer.pubsub_patterns 链表中
-
举个例子,下图展示了一个包含两个模式的
pubsub_patterns
链表, 其中client123
和client256
都正在订阅tweet.shop.*
模式: -
如果这时客户端
client10086
执行PSUBSCRIBE broadcast.list.*
, 那么pubsub_patterns
链表将被更新成这样: -
通过遍历整个
pubsub_patterns
链表,程序可以检查所有正在被订阅的模式,以及订阅这些模式的客户端。 -
假设客户端同时订阅了某种模式和符合该模式的某个频道,那么发送给这个频道的消息将被客户端接收到两次,只不过这两条消息的类型不同,一个是message类型,一个是pmessage类型,但其内容相同。
-
-
-
pubsub 命令: 查看订阅与发布系统状态
-
**格式:**PUBSUB CHANNELS [pattern]
-
eg :
-
PUBSUB CHANNELS 列出订阅与发布系统中的所有活跃频道。
-
PUBSUB CHANNELS news.i* 列出以news.i*开头的所有活跃频道。
-
返回由活跃频道组成的列表,即可以查询订阅与发布系统的状态
-
-
-
publish 命令: 将信息发送到指定的频道
-
格式:PUBLISH channel message
-
底层原理:
-
发送信息到模式的工作也是由 PUBLISH 命令进行的。PUBLISH 除了将 message 发送到所有订阅 channel 的客户端之外,它还会将 channel 和 pubsub_patterns 中的模式进行对比,如果 channel 和某个模式匹配的话,那么也将 message 发送到订阅那个模式的客户端。
-
下图展示了一个带有频道和模式的例子, 其中
tweet.shop.*
模式匹配了tweet.shop.kindle
频道和tweet.shop.ipad
频道, 并且有不同的客户端分别订阅它们三个:图片例子:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pTIkI6T7-1595674764373)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1595590358536.png)] -
当有信息发送到
tweet.shop.kindle
频道时, 信息除了发送给clientX
和clientY
之外, 还会发送给订阅tweet.shop.*
模式的client123
和client256
: -
另一方面, 如果接收到信息的是频道
tweet.shop.ipad
, 那么client123
和client256
同样会收到信息: -
其返回值为接收到该消息的订阅者的数量
-
-
-
punsubscribe 命令: 退订所有给定模式的频道
-
格式: PUNSUBSCRIBE [pattern [pattern …]]
-
原理:
- 这个命令执行的是订阅模式的反操作:程序会删除redisServer.pubsub_patterns 链表中,所有和被退订模式相关联的 pubsubPattern 结构,这样客户端就不会再收到和模式相匹配的频道发来的信息。
-
-
注意:
- 在SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE和PUNSUBSCRIBE命令中,
其返回值都包含了该客户端当前订阅的频道和模式的数量,当这个数量变为0时,该客户端会自动退出订阅状态。 - PUBLISH和SUBSCRIBE的缺陷在于客户端必须一直在线才能接收到消息,断线可能会导致客户端丢失消息,除此之外,旧版的redis可能会由于订阅者消费不够快而变的不稳定导致崩溃,甚至被管理员杀掉。
- 在SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE和PUNSUBSCRIBE命令中,
-
只要大家简单看一下pubsub.c这个源代码文件,差不多都会懂得
四,redis与其他中间件的区别
-
Redis发布订阅与ActiveMQ的比较
-
ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等,并且支持JMS规范,但Redis没有提供对这些协议的支持。
-
ActiveMQ提供持久化功能,但Redis无法对消息持久化存储,一旦消息被发送,如果没有订阅者接收,那么消息就会丢失。
-
ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端,Redis没有提供消息传输保障。
-
-
Redis发布订阅与RabbitMQ区别
五,使用场景
- 构建实时消息系统,比如普通的即时聊天,群聊等功能
- 在我们的分布式架构中,常常会遇到读写分离的场景,在写入的过程中,就可以使用redis发布订阅,使得写入值及时发布到各个读的程序中,就保证数据的完整一致性
- 在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们等功能
- 在我们的分布式架构中,常常会遇到读写分离的场景,在写入的过程中,就可以使用redis发布订阅,使得写入值及时发布到各个读的程序中,就保证数据的完整一致性
- 在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们