本文是大数据系列第 42 篇,深入分析 Redis Pub/Sub 的发布订阅机制、弱事务特性及其在分布式系统中的适用边界。
核心概念
Redis Pub/Sub 是一种消息通信模式,发布者(Publisher)和订阅者(Subscriber)都是 Redis 客户端,频道(Channel)存在于服务端。三者解耦,发布者无需知道谁在订阅,订阅者也无需关心谁在发布。
基础命令
# 订阅一个或多个频道
SUBSCRIBE channel1 channel2
# 模式订阅(支持通配符)
PSUBSCRIBE news.*
# 向频道发布消息
PUBLISH channel message
# 取消订阅
UNSUBSCRIBE channel1
PUNSUBSCRIBE news.*
工作机制
Pub/Sub 的运行遵循以下原则:
- 消息不持久化:Redis 不保存消息,消息仅推送给当前已连接的订阅者
- Fire-and-Forget 模型:消息发出后不等待任何确认,也不做重试
- 自动取消订阅:客户端断开连接后,订阅关系自动失效
订阅者执行 SUBSCRIBE 后进入阻塞接收模式,此时只能执行订阅相关命令(SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE、PUNSUBSCRIBE、PING),不能执行其他 Redis 命令。
弱事务三大缺陷
Redis Pub/Sub 被称为”弱事务”模型,主要体现在以下三点:
1. 投递不可靠
消息发布时如果没有活跃订阅者,消息立即丢弃。典型场景:系统扩容新增消费者节点时,扩容前已发布的消息对新消费者完全不可见。
2. 无确认机制
发布者发出消息后,无法得知哪些订阅者收到了消息、是否处理成功。这导致无法实现可靠投递语义(at-least-once 或 exactly-once)。
3. 无重试逻辑
网络抖动或消费者故障期间发布的消息,Redis 不会自动重发。消息永久丢失,没有死信队列(Dead Letter Queue)机制兜底。
生产环境风险
| 场景 | 风险 |
|---|---|
| 移动客户端断线重连 | 断线期间所有消息丢失 |
| 消费者服务重启 | 重启期间消息无法补偿 |
| 网络分区 | 消息单向丢失,无感知 |
| 水平扩容消费者 | 扩容前消息对新节点不可见 |
Redis 事务(MULTI/EXEC)的弱点
与 Pub/Sub 类似,Redis 事务也有弱事务特性:
- 不支持回滚:EXEC 执行过程中某条命令出错,其他命令仍会继续执行
- 不支持隔离性:MULTI 到 EXEC 之间,其他客户端可以插入命令(需配合 WATCH 实现乐观锁)
- 设计取舍:Redis 刻意牺牲部分 ACID 特性换取高吞吐量
MULTI
SET key1 value1
SET key2 value2
EXEC
替代方案选择
| 需求 | 推荐方案 |
|---|---|
| 消息可靠投递 + 持久化 | Redis Stream |
| 高吞吐 + 分布式消费 | Apache Kafka |
| 企业级消息队列 | RabbitMQ |
| 简单实时广播(允许丢消息) | Redis Pub/Sub |
结论:Redis Pub/Sub 适合对消息丢失不敏感的实时广播场景(如在线用户状态推送、实时通知),不适合金融交易、订单状态变更等对消息可靠性有强要求的场景。需要可靠消息队列时,优先考虑 Redis Stream 或 Kafka。