redis pub/sub不支持防堆积,消息不积压而直接丢弃;因输出缓冲区满导致强制断连且不重试、不落盘,故无法保障至少一次语义,关键业务应改用lpush/brpop或xadd/xreadgroup等可靠方案。

Redis PUB/SUB 本质不支持“防堆积”,只能预防断连和丢消息——因为消息根本不会积压,而是直接丢弃。
为什么PUB/SUB里看不到“堆积”,却会丢消息
发布者调用 PUBLISH 返回非零值,只代表消息已写入每个订阅者的输出缓冲区;一旦某个客户端读取太慢,它的 output_buffer 涨满,Redis 就强制断开该连接,且不重试、不落盘、不排队。所有未读消息永久丢失。
常见现象包括:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
INFO clients中client_longest_output_list持续 > 1000 - Redis 日志出现
Client X exceeded output buffer limit - 订阅端突然收不到消息,但
PUBLISH仍返回成功 - 加更多消费者后,CPU 和内存反而飙升(广播复制开销线性增长)
别在SUBSCRIBE端“提速”,要从PUBLISH端“控速”
你无法给单个订阅者限流,也不能让 PUBLISH 等它跟上。真正能做的,是让发布端主动适应消费能力:
- 用
RateLimiter控制PUBLISHQPS(例如限制为 50/s),避免突发打爆缓冲区 - 高频事件必须聚合:把“1秒内12次库存变更”合并成一条
{"item_id": "A", "delta": -12}再发 - 关键业务禁止用 PUB/SUB 做最终一致性保障——它连“至少一次”语义都不满足
- 监控
PUBSUB NUMSUB channel_name,发现长期为 0 的频道及时下线,避免无效匹配开销
真要保留消息可靠性,必须换底层模型
继续硬扛 PUB/SUB,所有重连、扩容、调参都是临时止痛。生产环境应切换到有背压能力的方案:
- 轻量级替代:
LPUSH+BRPOP队列,天然阻塞等待,消费不动就不给新消息 - 带 ACK 和历史回溯:
XADD+XREADGROUP,必须显式XACK,否则消息永远卡在 PEL - 别用
MAXLEN清 Stream,改用XTRIM mystream MINID ~<safe_id></safe_id>,safe_id来自所有消费者组中最小的已处理 ID - Spring Boot 中创建消费者组时,必须显式传
StreamOffset.latest(),别依赖默认值(可能从头重放)
最容易被忽略的一点:PUB/SUB 的语义是「通知」,不是「交付」。只要有一条没收到,链路就断了。解耦速率差,不是靠调缓冲区大小,而是靠划清边界——发布端只管写,订阅端按需拉。










