Redis Pub/Sub 消息持久化问题详解
Pub/Sub 的核心特点:即发即忘
Redis Pub/Sub(发布/订阅)是一种消息通信模式,它的核心设计理念是 “即发即忘”(fire and forget):
发布者 → Redis Channel → 订阅者(接收时在线)
→ 订阅者(离线 → 消息丢失)
关键特性:
– 消息 不持久化,发送后即被丢弃
– 离线订阅者 无法收到 离线期间的消息
– Redis 不存储消息,只是转发
Pub/Sub 消息模型
基本操作
# 订阅者
SUBSCRIBE news:sports # 订阅频道
SUBSCRIBE news:* # 不支持通配符,需用 PSUBSCRIBE
PSUBSCRIBE news:* # 模式订阅
# 发布者
PUBLISH news:sports "球赛结果:3-1" # 发布消息
消息流转过程
PUBLISH news:sports "消息内容"
↓
Redis 查找该频道的所有订阅者
↓
向每个订阅者推送消息
↓
消息推送完成后立即丢弃
(无论是否送达成功)
Pub/Sub 的可靠性问题
1. 消息不持久化
# 订阅者连接断开
# 此时发布者发送 10 条消息
PUBLISH channel "msg1"
PUBLISH channel "msg2"
# ... 10 条消息全部丢失
# 订阅者重连
SUBSCRIBE channel # 只能收到重连后的消息
2. 没有消息确认机制
- 发布者不知道消息是否被成功接收
- Redis 不关心订阅者是否真的收到了消息
- 网络抖动会导致消息丢失而无人知晓
3. 缓冲区溢出
# client-output-buffer-limit 配置
client-output-buffer-limit pubsub 32mb 8mb 60
- 每个订阅者维护一个输出缓冲区
- 如果订阅者消费慢,缓冲区满后 Redis 会断开连接
- 断开期间的消息全部丢失
4. 模式订阅的额外风险
PSUBSCRIBE news:* # 可能匹配大量频道
# 高频发布导致缓冲区快速填满
# 连接被强制断开
为什么 Pub/Sub 不做持久化
Redis 的设计哲学
- 定位不同:Pub/Sub 是即时消息通道,不是消息队列
- 性能优先:不做持久化,转发速度极快(微秒级)
- 内存管理:存储消息会消耗大量内存,违背 Redis 作为缓存的定位
与其他 Redis 消息模式的对比
| 特性 | Pub/Sub | Stream | List (BLPOP) |
|---|---|---|---|
| 消息持久化 | ❌ | ✅ RDB/AOF | ✅ RDB/AOF |
| 离线消息 | ❌ 丢失 | ✅ 可回溯 | ✅ 堆积 |
| 消息确认 | ❌ | ✅ XACK | ✅ 弹出即确认 |
| 广播支持 | ✅ | ✅ 多消费者组 | ❌ |
| 消费者组 | ❌ | ✅ | ❌ |
适用场景
Pub/Sub 适合的场景
- 实时通知:如 WebSocket 广播、实时排行榜更新
- 轻量级事件:缓存失效通知、配置变更广播
- 即时聊天:内存聊天室(不需要消息历史)
- 监控告警:实时指标推送
不适合的场景
- 订单处理:消息不能丢失,需要持久化
- 任务调度:需要可靠投递和重试
- 日志收集:数据需要持久化和回溯
- 重要通知:订阅者离线时必须保留
如果需要持久化怎么办?
方案一:改用 Redis Stream
# 用 Stream 实现持久化 Pub/Sub
# 生产者
redis.xadd('notification:channel', {'event': 'user_login', 'uid': '123'})
# 消费者(每个消费者独立消费者组)
redis.xreadgroup('notification:group', 'consumer1',
{'notification:channel': '>'})
方案二:Pub/Sub + Stream 组合
# Pub/Sub 做实时推送
# Stream 做持久化备份
# 接收消息的进程
def on_message(channel, data):
# 1. 实时推送给当前在线订阅者
send_to_online_subscribers(channel, data)
# 2. 同时持久化到 Stream
redis.xadd(f'persist:{channel}', data)
# 离线订阅者重连时,从 Stream 拉取离线消息
def on_reconnect(user_id):
pending = redis.xreadgroup(f'group:{user_id}', 'consumer',
{f'persist:{channel}': '0'})
面试要点
- Pub/Sub 核心缺陷:消息不持久,离线即丢失
- 缓冲区溢出:消费慢+生产快=连接断开
- 无 ACK 机制:无法保证消息送达
- 适用场景:实时性 > 可靠性,消息价值短暂
- 面试高频题:对比 Pub/Sub vs List vs Stream 的消息模型
- 如果问”如何让 Pub/Sub 可靠”,正确的回答是改用 Stream
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容