Redis发布订阅
redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
Redis客户端可以订阅任意数量的频道
零基础可以先这样理解:
Redis Pub/Sub 是一个轻量级广播通道。发布者把消息发到频道,所有正在订阅这个频道的客户端都会立刻收到。
它适合在线通知、实时广播、简单聊天室等场景,但它不是可靠消息队列:订阅者离线时不会补收历史消息,也没有消费确认和重试。
为什么需要发布订阅
发布订阅解决的是“一条消息同时通知多个在线订阅者”的问题。
如果不用发布订阅,发布者需要知道每个接收者是谁,然后逐个调用:
flowchart TD
A["发布者"] --> B["调用客户端 A"]
A --> C["调用客户端 B"]
A --> D["调用客户端 C"]这样发布者和接收者强耦合,新增订阅者就要改发布逻辑。
使用 Pub/Sub 后:
flowchart TD
A["发布者"] --> B["Redis Channel"]
B --> C["订阅者 A"]
B --> D["订阅者 B"]
B --> E["订阅者 C"]发布者只关心频道,不关心谁订阅。订阅者在线时就能收到消息。
风险边界
Redis Pub/Sub 的风险在于它只做实时广播,不做可靠投递:
| 风险 | 后果 |
|---|---|
| 订阅者离线 | 离线期间的消息不会补发 |
| 没有 ACK | 发布者不知道订阅者是否处理成功 |
| 没有重试 | 处理失败不会自动重新投递 |
| 不适合堆积 | 不能像 MQ 一样承接大量未消费消息 |
所以它适合实时通知,不适合订单创建、支付成功、库存扣减这类必须可靠处理的业务事件。
工作原理图
flowchart TD
A["Client A\nSUBSCRIBE news"] --> B["Redis Server"]
C["Client B\nSUBSCRIBE news"] --> B
D["Publisher\nPUBLISH news hello"] --> B
B --> E{"查找频道 news\n对应的订阅客户端链表"}
E --> F["把 hello 推送给 Client A"]
E --> G["把 hello 推送给 Client B"]
H["Client C 未订阅或离线"] -. "不会收到历史消息" .-> BRedis 服务端内部会维护一个字典:key 是频道名,value 是订阅这个频道的客户端列表。发布消息时,Redis 找到频道对应的客户端列表,然后逐个推送。
订阅/发布消息图
下图展示了频道channel1,以及订阅这是三个频道的三个客户端--client2、client5、和client1之间的关系 
当有新消息通过publish命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端 
命令
这些命令被广泛用于构建即时通信应用,比如聊天室(chatroom)和实时广播、实时提醒等 
测试
订阅端:
127.0.0.1:6379> SUBSCRIBE lpx #订阅一个频道 lpx
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "lpx"
3) (integer) 1
#等待读取信息
1) "message" #消息
2) "lpx" #频道
3) "hello,lpx" #内容
1) "message"
2) "lpx"
3) "hello,redis"发送端:
127.0.0.1:6379> PUBLISH lpx "hello,lpx" #发布者发布消息到频道
(integer) 1
127.0.0.1:6379> PUBLISH lpx "hello,redis" #发布者发布消息到频道
(integer) 1原理
Redis是使用C实现的,通过分析Redis源码里的pubsub.c文件,了解发布和订阅的底层实现,其次加深对redis的理解。
Redsi通过PUBLISH、SUBSCRIBE和PSUBSCRIBE等命令实现发布和订阅功能。
通过SUBSCRIBE命令订阅某频道后,redis-server里维护了一个字典,字典的键就是一个个channel(频道),而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。SUBSVRIBE命令的关键,就是将客户端添加到给定channel的订阅链表中。
通过PUBLISH命令向订阅者发布消息,redis-server会使用给定的频道作为键,在它维护的channel字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
PUB/SUB从字面上理解就是发布(publish)与订阅(subscrible),在Redis中,你可以设定对某一个key值进行消息发布及订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景
1、实时消息系统
2、实时聊天(频道作为聊天室,将信息回显给所有人即可)
3、订阅、关注系统
稍微复杂的场景就会使用消息中间件来实现例如:MQ
Pub/Sub 和 MQ 的区别
| 对比点 | Redis Pub/Sub | RocketMQ / RabbitMQ 等 MQ |
|---|---|---|
| 离线消息 | 不保存,离线收不到 | 通常可持久化,消费者上线后继续消费 |
| 消费确认 | 没有 ACK | 通常有 ACK、重试、死信 |
| 消息堆积 | 不适合大量堆积 | 适合削峰、异步解耦 |
| 典型用途 | 在线通知、广播 | 订单事件、异步任务、可靠投递 |
