Skip to content

第九章 发布/订阅(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.sportnews.tech
PUNSUBSCRIBE [pattern ...]取消模式订阅

模式支持 *(任意字符)、?(单个字符)、[abc](字符集)等 glob 风格(与 Redis 文档一致)。

用两个 redis-cli 终端演示完整流程

终端 1(订阅者)——先打开,执行订阅:

text
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,发布消息:

text
127.0.0.1:6379> PUBLISH chat.room1 "大家好"
(integer) 1

返回的 1 表示有 1 个客户端收到了这条推送。

回到终端 1,会看到类似输出:

text
1) "message"
2) "chat.room1"
3) "大家好"

取消订阅可在订阅连接上执行(若你的客户端支持在订阅状态下输入命令):

text
UNSUBSCRIBE chat.room1

若需模式订阅示例,在终端 1 可改用:

text
PSUBSCRIBE news.*

终端 2 执行:

text
PUBLISH news.tech "Redis 更新"
PUBLISH news.sport "赛况"

两条都会推给匹配 news.* 的客户端。


9.3 适用场景

场景说明
实时通知后台任务完成、订单状态变更等,推给当前在线的管理端或用户端(需配合 WebSocket 等把消息送到浏览器)
聊天室 / 房间广播同一频道即同一房间,多人在线时即时看到消息(仍需应用层处理用户、鉴权、持久化若需要)
配置或缓存失效广播多实例应用订阅 config:reload,一台改配置后 PUBLISH,各实例刷新本地缓存

共同点:强调实时、可多订阅者同时收到,且能接受「没收到的消息就丢了」这一前提。


9.4 局限性

  1. 消息不持久化,离线消息丢失
    订阅者若当时未连接,期间发布的消息不会补发。Redis 不把 Pub/Sub 消息写入 RDB/AOF 作为「可回放」的队列。

  2. 没有消息确认机制
    推送出去即结束,没有消费者 ACK;网络抖动或客户端崩溃可能导致静默丢消息,Redis 不会替你重试。

  3. 不适合可靠消息传递
    不能做「至少一次投递」「顺序强保证(多频道/多实例下)」等队列级语义。若业务要求必达、可审计、可堆积,应使用 Redis Stream、专业 MQ 或数据库 Outbox 等方案。

理解这三点,可以避免在错误场景里误用 Pub/Sub。


9.5 Pub/Sub vs Stream 对比

Stream 是 Redis 5.0 引入的日志型数据结构,支持消费组、待处理列表(PEL)等,更接近「可持久、可重试」的消息流。

对比项Pub/SubStream
数据是否持久在 Redis 中否(仅在线推送)是(可设置 maxlen 等策略)
离线后能否补读历史不能可以(按 ID 范围读)
消费组 / 竞争消费有(XREADGROUP 等)
确认与重试有(ACK、PEL 中未确认消息)
实现复杂度相对较高
典型用途实时广播、简单通知任务队列、事件流、需可靠性的场景

选择建议:只要实时广播、允许丢消息,用 Pub/Sub;要堆积、重放、组内分摊、ACK,优先考虑 Stream 或其他 MQ。


本章小结

小节要点
9.1 模式发布者 → 频道 → 订阅者;与消息队列不同,偏广播、不存消息
9.2 命令SUBSCRIBE / PUBLISH / UNSUBSCRIBEPSUBSCRIBE 模式订阅;两终端可快速演示
9.3 场景实时通知、聊天广播、配置/缓存失效广播
9.4 局限不持久、无 ACK、不可靠
9.5 对比 Stream要可靠与可回放选 Stream(或 MQ);要简单实时广播选 Pub/Sub

下一章预告

第十章:主从复制与高可用将介绍 Redis 主从架构如何同步数据、读写分离的基本思路,以及哨兵(Sentinel)等与高可用相关的概念,帮助你理解单机之外的部署方式。

坚持是一种品格