Redis Pub/Sub 不保存历史消息是设计使然,因纯内存广播、无服务端存储、AOF/RDB/MONITOR 均不记录;替代方案是 Redis Stream,支持持久化、回溯与消费者组;兜底需外部同步写入+原子性保障。

Redis Pub/Sub 本身不存消息,断线就丢,查不到历史是设计使然,不是配置没开对。
为什么 PUBLISH 消息查不到历史
Pub/Sub 是纯内存广播通道,PUBLISH 命令执行完,消息只推给当前在线的 SUBSCRIBE 客户端,服务端不留副本。AOF、RDB、MONITOR 都不记录它——AOF 只记数据变更命令,MONITOR 是临时调试流,关掉就没了。
-
PUBSUB NUMSUB只返回当前订阅数,不带消息内容 -
redis-cli --monitor能看到实时PUBLISH流,但断连后丢失、不落盘、不支持按 channel 回溯 - 没有类似 Kafka 的 offset 或 Stream 的 ID,无法定位“第几条”
用 Redis Stream 替代 Pub/Sub 实现消息回溯
Stream 是 Redis 5.0+ 提供的持久化日志结构,天然支持历史读取、消费者组、ACK 确认,是 Pub/Sub 的可靠替代方案。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 发布改用
XADD stream_name * field value,消息自动带时间戳 ID(如1725530520123-0) - 订阅方用
XREAD BLOCK 0 STREAMS stream_name $从最新开始监听;或指定 ID 回溯,例如XREAD STREAMS stream_name 1725530000000-0 - 需要多播时,建多个消费者组:
XGROUP CREATE stream_name group1 $,每个组独立维护读取位置 - 注意:Stream 不自动清理,得配
MAXLEN或定期XTRIM,否则内存涨满
在不换协议的前提下补救历史消息
如果必须保留现有 Pub/Sub 接口,又想支持断线重连后拉取最近几条,只能靠外部存储兜底。
- 每次
PUBLISH时,同步写一份摘要到LPUSH history:channel_name "msg_id|ts|len",并用LTRIM控制长度(比如只留 100 条) - 客户端上线后先发
LRANGE history:channel_name 0 9,再SUBSCRIBE;服务端需确保写入和发布原子性(用pipeline或 Lua 脚本) - 摘要建议存
sha256(message)[:8]+strlen(message),避免大消息撑爆 list - 别用
KEYS扫描历史 key,性能差;命名统一用history:{channel},直接GET或LRANGE
真正难的不是存历史,而是让所有发布路径都经过同一层——只要有一个业务绕过中间层直连 PUBLISH,审计和回溯就断点。这比选 Stream 还关键。

















