Redis Pub/Sub消息不持久化,服务器重启后未消费的消息全部丢失;因其纯内存转发、不落盘、不维护订阅状态,且PUBLISH不写入AOF/RDB,故任何持久化配置均无效。

不在。Redis服务器重启后,所有未被实时消费的Pub/Sub消息全部丢失,且无法恢复。
为什么SUBSCRIBE之后收不到重启前发布的消息
Redis的Pub/Sub是纯内存、无状态的转发机制:消息不落盘、不建队列、不维护订阅者离线状态。只要客户端没在SUBSCRIBE连接活跃期间收到消息,它就永远消失了。
常见错误现象:
- 服务端重启后,客户端重连并
SUBSCRIBE,但收不到重启前PUBLISH过的消息 - 用
redis-cli手动测试时,先PUBLISH再开新窗口SUBSCRIBE,也收不到
根本原因:Redis没有为Pub/Sub设计任何持久化路径——save、bgsave、AOF重写、RDB快照,全都不保存频道、订阅关系或待投递消息。
配置文件里加appendonly yes也没用
AOF(Append Only File)只记录写命令(如SET、LPUSH),而PUBLISH命令本身不会写入AOF——它只是触发一次内存广播,不修改任何键。
验证方式:
- 开启AOF后执行
PUBLISH channel1 "hello",检查appendonly.aof文件,里面找不到这条命令 - 即使你把
publish命令手动写进AOF,重启时Redis也不会执行它(因为AOF只重放数据变更命令)
所以无论你配appendonly yes还是save 60 1000,对Pub/Sub消息零影响。
想不丢消息?别用原生Pub/Sub
如果你需要消息可靠投递、支持断线重连、能回溯历史,原生Pub/Sub不是解决方案,而是陷阱。
可选替代方案:
- 用
LPUSH+BRPOP模拟队列,配合消费者ACK和重试逻辑 - 接入专业消息中间件(如RabbitMQ、Kafka),它们有确认机制、持久化存储和重播能力
- 在应用层加一层“消息中转服务”:接收
PUBLISH后存到STREAM(Redis 5.0+),再由消费者从XREAD拉取
注意:STREAM虽支持持久化和消费者组,但它和Pub/Sub是两套独立机制——PUBLISH不会自动写入STREAM,必须显式用XADD。
PSUBSCRIBE匹配多个频道时消息重复的坑
如果一个客户端同时执行了SUBSCRIBE logs和PSUBSCRIBE logs.*,再向logs.error发消息,它会收到两条:一条message类型(来自频道订阅),一条pmessage类型(来自模式订阅)。
这容易导致业务逻辑重复处理,尤其在无幂等设计时。
规避建议:
- 避免在同一连接中混用
SUBSCRIBE和PSUBSCRIBE相同语义的频道 - 消费端统一按
type字段区分,对pmessage做去重或跳过 - 用
CLIENT LIST查当前连接的sub和psub计数,及时发现异常订阅状态
真正棘手的不是怎么写订阅逻辑,而是默认假设“消息会等我”——Redis Pub/Sub根本不这么认为。











