适用版本:Redis 7.2.x
Redis 除了做缓存、计数器、排行榜之外,还内置了一套非常轻量的消息通信机制——发布订阅(Pub/Sub)。
如果你以前接触过消息队列,可能会把 Redis 的发布订阅理解为“简化版的消息广播”。这个理解基本没问题:
- 发送方把消息发布到某个频道
- 订阅方订阅这个频道
- 只要频道上有新消息,订阅者就能立即收到
它非常适合做轻量、低门槛、实时性高的通知型场景,比如:
- 配置变更广播
- 聊天室消息分发
- 简单事件通知
- 服务间轻量信号传递
但与此同时,它也有明显边界:它不是可靠消息队列。理解这一点,比背命令更重要。
一、什么是发布订阅机制
发布订阅(Publish / Subscribe)的核心思想是“解耦消息发送者与接收者”。
在 Redis 中主要有三个角色:
- 发布者(Publisher):负责发送消息
- 频道(Channel):消息投递的主题
- 订阅者(Subscriber):订阅频道并接收消息
举个例子:
- 频道名:
news.tech - 发布者:业务服务 A
- 订阅者:服务 B、服务 C、调试客户端
只要服务 A 向 news.tech 发布消息,所有在线订阅 news.tech 的客户端都会收到。
二、Redis Pub/Sub 的工作方式
1. 基本流程
Redis 发布订阅的工作流程可以概括为:
- 订阅者使用
SUBSCRIBE channel订阅某个频道 - 发布者使用
PUBLISH channel message向频道发送消息 - Redis 把消息实时推送给当前在线的订阅者
注意这里有一个关键词:当前在线。
Redis Pub/Sub 不会像传统消息队列那样把消息持久保存起来,离线期间错过的消息,订阅者上线后是收不到的。
2. 它不是“先存后投”
这是初学者最容易误解的地方。
Redis Pub/Sub 更像“广播喇叭”,不是“消息仓库”。
- 有人在线听,就能听到
- 没人在线听,消息就直接过去了
- 不会自动补发历史消息
因此它适合通知,而不适合必须可靠送达的业务消息。
三、常用命令与示例
1. 基础订阅与发布
我们可以用两个终端来演示。
终端 A:订阅频道
redis-cli
127.0.0.1:6379> SUBSCRIBE order.created
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "order.created"
3) (integer) 1
终端 B:发布消息
redis-cli
127.0.0.1:6379> PUBLISH order.created "order_id=1001"
(integer) 1
此时终端 A 会收到:
1) "message"
2) "order.created"
3) "order_id=1001"
2. 订阅多个频道
SUBSCRIBE order.created order.paid order.cancelled
这样一个连接就可以同时接收多个频道的消息。
3. 模式订阅
Redis 支持按模式订阅:
PSUBSCRIBE order.*
当有以下频道发布消息时:
order.createdorder.paidorder.cancelled
都能被这个订阅者接收到。
4. 查看 Pub/Sub 状态
PUBSUB CHANNELS
PUBSUB NUMSUB order.created
PUBSUB NUMPAT
这些命令可以帮助我们查看:
- 当前有哪些频道
- 某个频道有多少订阅者
- 当前有多少模式订阅
四、Redis 7.x 中的分片发布订阅
在 Redis 7.x 中,还引入了 Sharded Pub/Sub(分片发布订阅),用于更适配集群环境。
常见命令有:
SSUBSCRIBE shard:notice
SPUBLISH shard:notice "hello"
SUNSUBSCRIBE shard:notice
它与普通 Pub/Sub 的主要区别在于:
- 普通 Pub/Sub 更偏向全局频道广播
- 分片 Pub/Sub 会结合槽位路由,更适合 Redis Cluster 场景
如果你当前仍然是单机或主从架构,先掌握普通 SUBSCRIBE / PUBLISH 即可;如果在 Redis Cluster 中设计广播能力,再进一步理解 SSUBSCRIBE / SPUBLISH 会更合适。
五、Pub/Sub 的特点与边界
1. 优点
Redis 发布订阅的优点很明显:
- 使用简单,命令非常少
- 延迟低,适合实时通知
- 无需单独部署消息中间件
- 对轻量级通知场景很方便
2. 局限性
但它的边界也同样明显:
- 消息不持久化
- 不保证可靠投递
- 订阅者离线会丢消息
- 没有消费确认机制
- 不适合复杂消息堆积与回溯场景
所以在设计业务时,千万不要把 Redis Pub/Sub 直接等同于 Kafka、RocketMQ 或 RabbitMQ。
六、配置与命令实践示例
1. 用于配置变更广播
比如后台系统更新了某项配置,希望多个应用实例立即感知:
PUBLISH config.reload "feature_x=true"
各个应用实例订阅:
SUBSCRIBE config.reload
收到消息后,应用主动重新加载本地缓存配置。
2. 用于简单聊天室消息分发
PUBLISH chat.room.1001 "user=tom: hello"
SUBSCRIBE chat.room.1001
这种做法适合原型验证或轻量实时通信,但如果要求历史消息、离线补偿、已读回执,就不适合只用 Pub/Sub。
3. 检查频道订阅情况
PUBSUB CHANNELS
PUBSUB NUMSUB chat.room.1001
如果你发现消息发出去了但没人收到,第一步就可以先检查:当前是否真的有订阅者在线。
七、常见问题
1. 为什么发布成功了,但订阅者没有收到?
常见原因有:
- 订阅者并不在线
- 订阅的是另一个频道名
- 使用了模式订阅,但模式不匹配
- 客户端连接被复用或中断
- 在集群模式下对频道路由理解有误
PUBLISH 返回值表示收到该消息的订阅者数量,如果返回 0,通常说明当前没有匹配订阅者在线。
2. 订阅连接还能执行普通命令吗?
通常不建议。
一旦客户端进入订阅模式,这个连接主要用于接收消息。实践中通常会:
- 普通业务命令使用一个连接池
- Pub/Sub 单独使用订阅连接
这样更清晰,也更稳定。
3. Pub/Sub 能不能保证消息不丢?
不能。
如果业务要求:
- 消息必须送达
- 消费失败可重试
- 能查看历史消息
- 支持消费组
那么应该考虑 Redis Streams 或专业消息队列,而不是单纯依赖 Pub/Sub。
4. Redis Pub/Sub 和 Streams 有什么区别?
一个简单理解方式:
- Pub/Sub:实时广播,轻量,但不可靠
- Streams:可保存消息、可回放、可消费组,适合更正式的消息处理场景
八、实践建议
1. 把 Pub/Sub 用在“通知”,不要硬扛“可靠消息”
适合的场景:
- 配置刷新通知
- 缓存失效广播
- 简单事件提醒
- 低价值、可丢失的实时信号
不太适合的场景:
- 订单消息主链路
- 支付结果投递
- 库存扣减通知
- 必须审计与回放的业务事件
2. 订阅连接要独立管理
不要把订阅连接和普通 Redis 读写连接混用。更常见的做法是:
- 一个连接专门负责订阅
- 收到消息后交给业务线程池处理
- 普通 Redis 访问仍走独立连接池
3. 消息体尽量简单,必要时只传 ID
Pub/Sub 消息更适合传递轻量内容。实践中常见模式是:
- 消息里只发对象 ID 或事件类型
- 消费端收到后再去查询详细数据
这样可以降低消息耦合,也能减小消息体积。
4. 集群环境提前确认是否需要分片 Pub/Sub
如果你使用 Redis Cluster,并且对广播范围、路由成本、槽位行为有明确要求,可以进一步考虑 SPUBLISH / SSUBSCRIBE。但如果只是入门和一般通知场景,先把普通 Pub/Sub 理解透更重要。
5. 重要链路优先考虑 Streams 或专业 MQ
如果你发现自己开始需要:
- 消费确认
- 失败重试
- 死信处理
- 消息积压
- 顺序消费
- 历史回放
那就说明场景已经超出 Pub/Sub 的舒适区了。
九、小结
Redis 发布订阅机制非常适合作为入门级、轻量级的消息广播方案。学习它时,建议重点记住以下几点:
- Pub/Sub 的本质是实时广播,不是可靠队列
- 消息只会发给当前在线订阅者,离线不会补发
SUBSCRIBE/PUBLISH适合轻量通知,SSUBSCRIBE/SPUBLISH适合集群分片场景- 一旦业务要求可靠性、可回放、可重试,就应该考虑 Streams 或更专业的 MQ
如果把 Redis Pub/Sub 用在它擅长的地方,它会非常顺手;如果把它当成完整消息中间件来使用,就容易踩坑。
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!