文章目录
- Redis发布与订阅
- 什么是发布订阅
- 为什么要用发布订阅
- 发布/订阅如何使用
- 基于频道
- 底层原理
- 分析
- 基于模式
- 分析
Redis发布与订阅
什么是发布订阅
Redis 发布订阅( pub/sub )是一种消息通信模式:发送者( pub )发送消息,订阅者( sub )接收消息。
Redis 客户端可以订阅任意数量的频道。
发布者可以建立许多个频道进行消息的发送(如上图频道1、频道2、频道3),供订阅者进行接收和监听消息。
1.客户端可以订阅频道,例如channel1频道
2.当发布者给这个频道发布消息后,消息就会发送给订阅的客户端
通俗的解读一下:1.发送者建立频道,2.订阅者去订阅这个频道,3.发布者往频道发送了消息,4.所有订阅频道的订阅者都会收到消息
为什么要用发布订阅
- 对比中间件,针对消息订阅发布功能,市面上很多大多使用的是kafka、RabbitMQ、ActiveMQ, RocketMQ等这几种,redis的订阅发布功能跟这三者相比,相对轻量,针对数据准确和安全性要求没有那么高可以直接使用,适用于小型项目。
- redis 的List数据类型结构提供了 blpop 、brpop 命令结合 rpush、lpush 命令可以实现消息队列机制,基于双端链表实现的发布与订阅功能
这种方式存在两个局限性:
- 不能支持一对多的消息分发。
- 如果生产者生成的速度远远大于消费者消费的速度,易堆积大量未消费的消息
发布/订阅如何使用
Redis有两种发布/订阅模式:
- 基于频道(Channel)的发布/订阅
- 基于模式(pattern)的发布/订阅
基于频道
序号 | 命令与描述 |
subscribe channel [channel … ] | 订阅给定的一个或多个频道 |
unsubscribe channel [channel … ] | 退订给定的频道 (说明:若没有指定channel,则默认退订所有频道) |
publish channel message | 将消息发送给指定频道 channel (返回结果:接收到信息的订阅者数量,无订阅者返回0) |
pubsub channels [argument [atgument …] ] | 查看订阅与发布系统的状态 说明:返回活跃频道列表(即至少有一个订阅者的频道,订阅模式的客户端除外) |
- 订阅者订阅频道 subscribe channel [channel …]
-------------客户端1(订阅者) :订阅频道 ---------------------
# 订阅 “tinker” 和 “csdn” 频道(如果不存在则会创建频道)
127.0.0.1:6379> subscribe tinker csdn
Reading messages... (press Ctrl-C to quit)
1) "subscribe" -- 返回值类型:表示订阅成功!
2) "tinker" -- 订阅频道的名称
3) (integer) 1 -- 当前客户端已订阅频道的数量
1) "subscribe"
2) "csdn"
3) (integer) 2
#注意:订阅后,该客户端会一直监听消息,如果发送者有消息发给频道,这里会立刻接收到消息
- 发布者发布消息 publish channel message
-------------客户端2(发布者):发布消息给频道 ---------------
# 给“tinker”这个频道 发送一条消息:“I am tinker”
127.0.0.1:6379> publish tinker "I am tinker"
(integer) 1 # 接收到信息的订阅者数量,无订阅者返回0
- 客户端2 (发布者) 发布消息给频道后,此时我们再来观察 客户端1 (订阅者) 的客户端窗口变化:
---------变化如下:(实时接收到了该频道的发布者的消息)------
1) "message" -- 返回值类型:消息
2) "tinker" -- 来源(从哪个频道发过来的)
3) "I am tinker" -- 消息内容
底层原理
底层通过字典实现。pubsub_channels 是一个字典类型,保存订阅频道的信息:字典的key为订阅的频道, 字典的value是一个链表, 链表中保存了所有订阅该频道的客户端
分析
频道订阅:订阅频道时先检查字段内部是否存在;不存在则为当前频道创建一个字典且创建一个链表存储客户端id;否则直接将客户端id插入到链表中。
取消频道订阅:取消时将客户端id从对应的链表中删除;如果删除之后链表已经是空链表了,则将会把这个频道从字典中删除。
发布:首先根据 channel 定位到字典的键, 然后将信息发送给字典值链表中的所有客户端
基于模式
如果有某个/某些模式和该频道匹配,所有订阅这个/这些频道的客户端也同样会收到信息。
序号 | 命令与描述 |
psubscribe pattern1 [pattern…] | 订阅一个或多个符合给定模式的频道 说明:每个模式以 * 作为匹配符;例如 cn* 匹配所有以cn开头的频道:cn.java、cn.csdn |
punsubscribe [pattern [pattern …] ] | 退订所有给定模式的频道 说明:pattern 未指定,则订阅的所有模式都会被退订,否则只退订指定的订阅的模式 |
分析
简单解释一下:这里的模式跟RabbitMQ的topic模式相似,采用*来做通配符,*表示任何一个词,只要能匹配上就会接收到消息
通配符中?表示1个占位符,*表示任意个占位符(包括0),?*表示1个以上占位符。