Redis发布订阅内存会随订阅者数量线性上涨,因每个订阅者独占output_buffer且PUBLISH需为每个客户端拷贝消息;必须显式配置client-output-buffer-limit pubsub硬限、软限和超时,否则易OOM。

大,而且是线性增长的硬伤——每多一个订阅者,PUBLISH 就得多做一次内存拷贝 + socket 写入,主线程同步扛,没法并行。
为什么内存会随订阅者数量线性上涨
Redis 不存消息,但每个活跃订阅者都独占一块 output_buffer。只要消费跟不上,这块缓冲区就持续膨胀,且不受 maxmemory 约束。
-
PUBLISH时,主线程遍历所有订阅该频道的客户端链表,逐个把消息序列化后复制进各自的output_buffer - 缓冲区积压后,
CLIENT LIST中的omem字段会飙升(常见几十 MB,极端 case 达 GB 级) -
INFO clients里mem_clients_pubsub占比突增,就是内存被卡在输出缓冲区的明确信号 - 频道名本身也吃内存:每个
SUBSCRIBE channel都会让 Redis 在内部pubsub_channels字典里存一份键,频道名越长、数量越多,字典开销越不可忽视
client-output-buffer-limit pubsub 必须显式配置
默认值形同虚设,不配等于埋雷。线上环境必须写死硬限制,否则单个卡住的订阅者就能拖垮整机。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 正确格式:
client-output-buffer-limit pubsub 32mb 8mb 60(硬限 32MB,软限 8MB,超时 60 秒) - 硬限建议设为物理内存的 5%~10%,比如 64GB 机器设
32mb起步 - 软限设为硬限的 1/4~1/2,留出反应窗口;时间窗口别设太短(
- 改完要
CONFIG REWRITE或重启,且必须同步到所有集群节点
频道名和连接数才是隐藏的内存放大器
很多人只盯 omem,却忽略频道元数据和连接本身的开销。
- 避免动态拼接长频道名,比如不用
user:123456789:notification:order:status:update,改用u123:ntf:ord:st或哈希截断(如sha256("user:123456789:")[0:8]) - 检查真实负载:
redis-cli pubsub numsub channel*对比redis-cli info clients | grep connected_clients,确认是不是“连接数多但频道空闲” - 用
PUBSUB CHANNELS和PUBSUB NUMPAT巡检频道爆炸风险:返回结果 >500 个频道或 >10 个模式订阅,就得立刻干预 - 通配符订阅(
PSUBSCRIBE order.*)比精确订阅慢一个数量级,慎用
真正危险的不是“有多少人订阅”,而是“有多少人订了但从不读”。缓冲区积压、频道泛滥、连接失控,三者叠加才让内存失控——监控 omem、收紧 client-output-buffer-limit、砍掉无效频道,缺一不可。

















