- 什么是发布订阅
- Redis发布订阅(pub/sub)是一种消息通讯模式,发送者(pub)发送消息,订阅者(sub)接收消息。
- Redis客户端可以通过广播的方式将消息(message)同时发送给可能存在的多个客户端,并且发送消息的客户端不需要知道接受消息的客户端的具体信息。(发布消息的客户端和接收消息的客户端两者之间没有直接联系)
- 客户端可以订阅(subscribe)任意数量的频道(channel),每当有新消息被发送到订阅的频道时,信息就会被发送给所有订阅指定频道的客户端。
- 一个频道可以被多个客户端订阅,一个客户端也可以订阅多个频道。
- 使用场景
- 实时沟通消息系统
- 微信公众号(点击关注即订阅该公众号,公众号发布博文后,订阅的用户就可以监听到)
- 粉丝关注
- 文章推送
- 电商中,用户下单成功后向指定频道发送消息,下游业务订阅支付结果处理后续业务。
-
图解
三个客户端分别订阅channel1和channel2 2个频道
发布者(publisher)向channel1频道发送了的消息被channel1的订阅者client1、client2、client3同时接收到,发布者向channel2发送的消息只能被channel2的订阅者client2、client3接收到,client1无法接收
命令行实现
- 客户端订阅channel1频道(客户端1)
# 订阅1个或者多个频道subscribe channel [channel ... ]
subscribe channel1
- 给channel1频道发送消息 hello(客户端2)
publish channel hello
# 返回频道订阅者的数量
- 打开客户端1可以看见发送的消息
- 退订频道
unsubscribe channel [channel ... ]
- 查看订阅与发布系统的状态
pubsub channels [argument [atgument ...] ]
- 为什么要使用发布和订阅
- 消息发送订阅功能很多大厂使用的是kafka、RabbitMQ、ActiveMQ、RocketMQ等消息队列,redis的发布订阅比较前者相对轻量,对于数据安全性要求不高的公司可以直接使用
- redis的List数据结构提供了blpop、brpop命令结合rpush、lpush可以实现消息队列机制,可以基于双端链表实现消息的发布与订阅(比较笨重,不如直接使用发布订阅功能)
- 不支持一对多的消息发送
- 如果生产者的速度远远大于消费者,容易堆积大量未消费的信息
- 双端队列只能有一个或者多个消费者轮着去消费,但是不能将消息同时发送给其他消费者
- redis发布订阅模式,生产者生产完消息直接通过频道分发消息给订阅了该频道的所有消费者
- 两种实现模式
- 上述4为“基于频道”的发布订阅模式
- 基于模式配(pattern)的发布订阅模式
- 订阅一个或者多个符合给定模式的频道,每个模式以作为匹配符;例如cn 匹配所有以cn开头的频道
psubscribe pattern1 [pattern...]
# 订阅者订阅频道 订阅a?和com.*两种模式的频道 ?表示一个占位符 a?表示匹配 aa、ab、ac等a开头的两个字符的频道
psubscribe a? com.*
# 发布者发布消息
publish ahead "hello" ——————(integer 1) 发布失败,没有订阅者
publish aa "hello"——————(integer 1) 有1个匹配着
publish com.cn "hello"——————(integer 1) 有1个匹配着
- 退订所有指定模式的频道,如果pattern未指定则订阅的所有模式都被退订
punsubscribe [pattern [pattern ...] ]
- 实现原理
- 基于频道模式
- 由底层字典实现,所有pubsub_channels是一个字典类型。字典的key为订阅的频道,value为一个链表,链表中保存了所有订阅该频道的客户端
- 基于匹配模式
- 底层由pubsub_pattern节点的链表实现
- 新增一个pubsub_pattern数据结构添加到链表的最后尾部,同时保存客户端ID
-
取消订阅模式:从当前的链表pubsub_pattern结构中删除需要取消的pubsub_pattern结构