第九章 发布/订阅(Pub/Sub)
发布/订阅(Publish/Subscribe,简称 Pub/Sub)是 Redis 提供的一种消息广播能力:发送方把消息发到某个「频道」,所有正在订阅该频道的客户端都会立刻收到。本章介绍概念、常用命令、典型场景与局限,并和 Stream 做简要对比,便于你选对工具。
9.1 什么是发布/订阅模式
概念
- 发布者(Publisher):向指定频道发送消息,不关心谁会收到。
- 频道(Channel):一个字符串名字,类似「话题」或「房间名」。
- 订阅者(Subscriber):监听一个或多个频道,有新消息时由 Redis 推送给客户端。
可以把 Redis 看成中间的交换机:发布者只对接频道,订阅者只对接频道,彼此不需要知道对方是谁。
ASCII 示意图
+------------------+
Publisher A ---->| |
| Redis |---- Subscriber 1 (订阅 news)
Publisher B ---->| (Pub/Sub) |
| |---- Subscriber 2 (订阅 news)
+------------------+
|
+----------> Subscriber 3 (订阅 weather)上图表示:多个发布者可以向不同频道发消息;每个订阅者只接收自己订阅的频道上的消息。
与消息队列的区别
| 对比项 | Pub/Sub(Redis) | 典型消息队列(如 RabbitMQ、Kafka 等) |
|---|---|---|
| 消息是否被「消费掉」 | 广播给所有当前订阅者,不排队留存 | 通常有队列/分区,消费者按策略拉取或投递 |
| 离线能否收到历史消息 | 不能(未订阅时发的消息收不到) | 常可持久化,消费者可稍后补消费 |
| 是否保证送达 | 不保证(无 ACK) | 常有确认、重试、死信等机制 |
| 典型用途 | 实时通知、广播、简单解耦 | 可靠异步任务、削峰、事件溯源等 |
一句话:Pub/Sub 像「广播电台」——当时开着收音机的人才能听见;消息队列像「信箱」——信可以暂存,你晚点来取。
9.2 基本命令
SUBSCRIBE / PUBLISH / UNSUBSCRIBE
| 命令 | 作用 |
|---|---|
SUBSCRIBE channel [channel ...] | 订阅一个或多个频道,阻塞等待消息 |
PUBLISH channel message | 向频道发布一条字符串消息,返回收到推送的客户端数量 |
UNSUBSCRIBE [channel ...] | 取消订阅;不写频道则取消当前连接上的所有订阅 |
注意:进入 SUBSCRIBE 状态后,该 redis-cli 连接主要用于收消息,一般不再混用普通读写命令(行为以客户端实现为准)。
PSUBSCRIBE(模式匹配订阅)
| 命令 | 作用 |
|---|---|
PSUBSCRIBE pattern [pattern ...] | 按模式订阅,如 news.* 可匹配 news.sport、news.tech |
PUNSUBSCRIBE [pattern ...] | 取消模式订阅 |
模式支持 *(任意字符)、?(单个字符)、[abc](字符集)等 glob 风格(与 Redis 文档一致)。
用两个 redis-cli 终端演示完整流程
终端 1(订阅者)——先打开,执行订阅:
127.0.0.1:6379> SUBSCRIBE chat.room1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "chat.room1"
3) (integer) 1之后该终端会阻塞,等待消息。
终端 2(发布者)——另开一个 redis-cli,发布消息:
127.0.0.1:6379> PUBLISH chat.room1 "大家好"
(integer) 1返回的 1 表示有 1 个客户端收到了这条推送。
回到终端 1,会看到类似输出:
1) "message"
2) "chat.room1"
3) "大家好"取消订阅可在订阅连接上执行(若你的客户端支持在订阅状态下输入命令):
UNSUBSCRIBE chat.room1若需模式订阅示例,在终端 1 可改用:
PSUBSCRIBE news.*终端 2 执行:
PUBLISH news.tech "Redis 更新"
PUBLISH news.sport "赛况"两条都会推给匹配 news.* 的客户端。
9.3 适用场景
| 场景 | 说明 |
|---|---|
| 实时通知 | 后台任务完成、订单状态变更等,推给当前在线的管理端或用户端(需配合 WebSocket 等把消息送到浏览器) |
| 聊天室 / 房间广播 | 同一频道即同一房间,多人在线时即时看到消息(仍需应用层处理用户、鉴权、持久化若需要) |
| 配置或缓存失效广播 | 多实例应用订阅 config:reload,一台改配置后 PUBLISH,各实例刷新本地缓存 |
共同点:强调实时、可多订阅者同时收到,且能接受「没收到的消息就丢了」这一前提。
9.4 局限性
消息不持久化,离线消息丢失
订阅者若当时未连接,期间发布的消息不会补发。Redis 不把 Pub/Sub 消息写入 RDB/AOF 作为「可回放」的队列。没有消息确认机制
推送出去即结束,没有消费者 ACK;网络抖动或客户端崩溃可能导致静默丢消息,Redis 不会替你重试。不适合可靠消息传递
不能做「至少一次投递」「顺序强保证(多频道/多实例下)」等队列级语义。若业务要求必达、可审计、可堆积,应使用 Redis Stream、专业 MQ 或数据库 Outbox 等方案。
理解这三点,可以避免在错误场景里误用 Pub/Sub。
9.5 Pub/Sub vs Stream 对比
Stream 是 Redis 5.0 引入的日志型数据结构,支持消费组、待处理列表(PEL)等,更接近「可持久、可重试」的消息流。
| 对比项 | Pub/Sub | Stream |
|---|---|---|
| 数据是否持久在 Redis 中 | 否(仅在线推送) | 是(可设置 maxlen 等策略) |
| 离线后能否补读历史 | 不能 | 可以(按 ID 范围读) |
| 消费组 / 竞争消费 | 无 | 有(XREADGROUP 等) |
| 确认与重试 | 无 | 有(ACK、PEL 中未确认消息) |
| 实现复杂度 | 低 | 相对较高 |
| 典型用途 | 实时广播、简单通知 | 任务队列、事件流、需可靠性的场景 |
选择建议:只要实时广播、允许丢消息,用 Pub/Sub;要堆积、重放、组内分摊、ACK,优先考虑 Stream 或其他 MQ。
本章小结
| 小节 | 要点 |
|---|---|
| 9.1 模式 | 发布者 → 频道 → 订阅者;与消息队列不同,偏广播、不存消息 |
| 9.2 命令 | SUBSCRIBE / PUBLISH / UNSUBSCRIBE;PSUBSCRIBE 模式订阅;两终端可快速演示 |
| 9.3 场景 | 实时通知、聊天广播、配置/缓存失效广播 |
| 9.4 局限 | 不持久、无 ACK、不可靠 |
| 9.5 对比 Stream | 要可靠与可回放选 Stream(或 MQ);要简单实时广播选 Pub/Sub |
下一章预告
第十章:主从复制与高可用将介绍 Redis 主从架构如何同步数据、读写分离的基本思路,以及哨兵(Sentinel)等与高可用相关的概念,帮助你理解单机之外的部署方式。