redis pub/sub 消息“丢失”实为输出缓冲区超限触发强制断连,因纯内存传输无持久化与确认机制;默认8mb硬限易被慢消费客户端打爆,需按业务节奏配置client-output-buffer-limit pubsub三参数,并监控omem防oom。

Redis 丢弃订阅消息,大概率不是“丢了”,而是 client-output-buffer-limit pubsub 触发了强制断连——缓冲区一超限,连接被杀,积压消息直接清空。
为什么 PUB/SUB 消息会突然消失
Redis 的 PUB/SUB 是纯内存管道,不落盘、不重试、不确认。发布者只管发,不管谁收、收没收到、收得快不快。一旦订阅客户端消费慢(比如网络抖动、应用卡顿、GC 停顿),消息就全堆在它的输出缓冲区里。缓冲区涨到硬限制(hard-limit)或持续超过软限制(soft-limit达 soft-seconds),Redis 就直接 close 连接,缓冲区内容全部丢弃。
- 典型现象:
CLIENT LIST中某 client 的omem字段飙升,cmd显示为subscribe或psubscribe,同时INFO memory的used_memory_human明显上涨,但db0:keys=xxx完全不变 - 默认配置下,
pubsub缓冲区硬限是 8MB(部分旧版甚至只有 2MB),软限是 2MB/60s —— 这对真实业务几乎不够用 - 一条
PUBLISH到 10 个订阅者,就是 10 份副本进 10 个缓冲区;哪怕只有一两个客户端卡住,几秒就能打爆
如何安全放宽 pubsub 输出缓冲区
不能只调大数字,得结合业务节奏设三个参数:硬限(hard-limit)、软限(soft-limit)、软限持续时间(soft-seconds)。三者顺序固定,缺一不可。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
client-output-buffer-limit pubsub 32mb 8mb 60是较稳妥的起点:硬限 32MB 防 OOM,软限 8MB + 60s 给足恢复窗口 - 如果客户端有心跳机制(例如每 30 秒发一次
PING),soft-seconds应设为心跳间隔的 1.5 倍(如 45),避免误杀 - 切勿把任一参数设为
0(即禁用限制):pubsub场景下等于放弃保护,OOM 风险极高 - 改完必须重启 Redis 或用
CONFIG REWRITE持久化,并验证:CONFIG GET client-output-buffer-limit
normal 类型缓冲区也得盯紧 pipeline 场景
别只盯着 pubsub,normal 类型在批量操作时一样会炸。尤其用 pipeline 发几十上百条命令,响应数据全堆在一个缓冲区里,soft-limit 极易误触发断连。
- 同步单次调用(如
GET bigjson):缓冲区峰值 ≈ 单次响应大小,hard-limit可略大于最大 value(如 12MB) - pipeline 批量请求:缓冲区需容纳所有未读响应,例如 100 条
HGETALL× 50KB = 至少 5MB,此时soft-limit更关键 - 生产环境建议:
client-output-buffer-limit normal 64mb 0 0—— 硬限设够,软限关闭(0表示不启用软限制),靠监控和告警兜底
光调参数还不够,必须加监控
缓冲区问题从不提前打招呼,等发现时往往已丢了一批消息。上线后必须建立常态化检查机制。
- 高频巡检:
redis-cli --csv CLIENT LIST | grep subscribe | awk -F',' '{print $1,$7}'(取 client id 和 omem) - 阈值告警:当任意 client 的
omem > 16mb或连续 2 次采样增长 > 2MB,立刻告警 - 关联指标:
used_memory_human异常升高但keyspace_hits无变化,基本可锁定是输出缓冲区问题 - 特别注意:输出缓冲区内存不走
maxmemory控制,它吃的是系统物理内存,超了直接 OOM kill 进程
缓冲区不是越大越好,但太小等于默认开启“消息丢弃模式”。真正难的不是改那行配置,而是理解你的客户端消费节奏、心跳周期、消息体平均大小——这些才是决定三个数字该填多少的依据。










