redis pub/sub消息不落盘,仅暂存于客户端输出缓冲区,不计入used_memory,但缓冲区膨胀会耗尽物理内存导致oom。

Redis 发布订阅(Pub/Sub)的消息确实不占用磁盘空间——这不是配置出来的效果,而是设计使然。 它压根不落盘、不写 AOF、不进 RDB,连 key 都不存在。你 PUBLISH 一条消息,Redis 就在内存里转一圈、发给订阅者、立刻丢弃,整个过程跟持久化模块完全无关。
Pub/Sub 消息到底存在哪?
只存在于每个订阅客户端连接的 输出缓冲区(output buffer) 中,且仅当该客户端还没来得及读走时才暂存。这个缓冲区是 per-connection 的,属于 Redis server 进程的堆内存,但 不计入 used_memory,也不受 maxmemory 和 maxmemory-policy 管控。
常见误解是“没配 AOF/RDB 就不会落盘”,其实根本不需要关——因为 Pub/Sub 从源头就绕开了所有持久化路径。
-
PUBLISH不会触发 AOF rewrite 或 RDB fork - 频道(channel)不是 key,
KEYS *查不到,DBSIZE不统计 - 哪怕你把
appendonly no和save ""全关了,Pub/Sub 行为也完全不变
为什么 INFO memory 里看不到 Pub/Sub 占用?
INFO memory 显示的 used_memory 只统计「键值对数据 + Redis 自身开销」,而 Pub/Sub 缓冲区被归类为「客户端连接上下文资源」,和 socket 读写缓冲、client query buffer 并列,走的是另一套内存统计口径。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
验证方式:
redis-cli INFO clients | grep client_longest_output_list redis-cli CLIENT LIST | grep -E "(addr|omem|cmd)"
你会看到某条连接的 omem 字段飙升,但 used_memory_human 纹丝不动——这就是纯内存转发最典型的信号。
不落盘 ≠ 不耗内存,容易踩的坑在这
虽然不写磁盘,但缓冲区膨胀照样吃光物理内存,且 OS OOM killer 会直接干掉 redis-server 进程,错误日志里连 OOM command not allowed 都不会出现,只有 Client closed connection due to output buffer limit reached。
- 默认
client-output-buffer-limit pubsub是32mb 8mb 60,但很多环境没显式配置,等于没限 - WebSocket 后端实例短暂失联,对应订阅连接的
omem可能在 10 秒内涨到 200MB+ - 调大硬限制(如设成
512mb)只是掩耳盗铃:它不解决消费滞后,反而让单个坏连接拖垮整机
真正要盯住的不是磁盘,而是每个连接的 omem 值和 client-output-buffer-limit 是否生效——毕竟消息不落盘,但内存会真实泄漏。










