redis订阅连接的输出缓冲区内存不受maxmemory限制,仅体现于used_memory_rss,需通过client-output-buffer-limit pubsub显式配置并监控client list的omem字段以防oom。

因为 Redis 为每个订阅连接单独维护一个输出缓冲区,消息积压会直接填充这个缓冲区,而该内存不走 maxmemory 管控,也不计入 used_memory,只体现在 used_memory_rss 里——它会无声无息吃光物理内存。
client-output-buffer-limit pubsub 不配等于没刹车
Redis 默认有内置值(如 8mb 2mb 60),但这是“存在”,不是“可用”。生产环境从不依赖默认:
- 该参数必须显式写进
redis.conf,CONFIG SET不支持动态修改 - 设为
0 0 0表示禁用保护,单个卡住的订阅者就能把整机内存撑爆 -
used_memory_dataset可能才几百 MB,used_memory_rss却飙到 20GB——这就是缓冲区在裸奔
CLIENT LIST 里 omem 字段才是真相
执行 redis-cli CLIENT LIST 后,盯住这几个字段:
-
omem=12456789:该连接输出缓冲区已占约 12MB 内存(单位字节) -
cmd=subscribe:说明它确实处于订阅状态,不是假连接 -
oll=456:还有 456 条消息待发,说明消费端完全没读
如果 omem 持续 >5MB 或多个连接同步上涨,基本可断定是消费逻辑阻塞(比如 Python 里用 redis-py 的 listen() 同步阻塞读,没做异步分发)或网络持续丢包。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
频道名太长也会悄悄吃内存
每个 SUBSCRIBE channel:xxx 都会让 Redis 在内部 dict 里存一份频道键,哪怕没人发过消息:
- 频道名越长、数量越多,dict 的哈希表扩容开销越大
- 不用
user:123456789:notification:order:status:update,改用u123:ntf:ord:st或 SHA256 截断前 8 位 -
redis-cli PUBSUB CHANNELS | wc -l超过 500 就该预警——跳表匹配成本开始指数级上升
缓冲区调大只是争取排查时间
调高 client-output-buffer-limit pubsub 能延缓断连,但不能解决根本问题:
- 硬限设太大(如
128mb)却不配监控告警,等于把 OOM 延期到更难抢救的时刻 - 大量连接
omem缓慢但稳定上涨,大概率是下游 HTTP 调用超时、数据库锁等待等外部依赖拖慢了消费 - 客户端连接未正确
UNSUBSCRIBE或复用混乱,会导致“僵尸订阅”长期占用缓冲区
真正要盯死的,是消费端的处理延迟、心跳保活机制,以及频道生命周期是否和业务事件强绑定——缓冲区从来不是问题本身,只是问题的第一个回声。










