Redis Pub/Sub内存飙升主因是客户端连接数多、消息积压、频道元数据膨胀三者叠加,而非订阅本身;其内存不计入used_memory,仅反映在used_memory_rss和进程实际占用中,需通过client-output-buffer-limit pubsub配置硬软限并重启生效来防控。

不是订阅本身吃内存,是客户端连接数多、未消费消息积压、频道元数据膨胀三者叠加造成的。 单纯增加 maxmemory 或换淘汰策略没用——Pub/Sub 不走键空间,不参与 maxmemory-policy 淘汰。
为什么 redis-cli info memory 看不到 Pub/Sub 内存上涨?
因为这部分内存不在 used_memory 统计里:每个订阅连接的输出缓冲区、每个频道名在内部 dict 中的条目,都算作 Redis 进程的“非键内存”,只反映在 used_memory_rss 和进程实际占用中。你看到 mem_fragmentation_ratio 突然飙高(比如 >2.0),往往就是缓冲区或 dict 膨胀的信号。
验证方式:
- 运行
redis-cli info clients | grep connected_clients查当前连接数 - 对比
redis-cli pubsub numsub channel*的结果——如果连接数远大于活跃频道数,说明大量空闲连接挂着没断开 - 执行
redis-cli --scan --pattern "your:channel:*" | wc -l估算频道基数,超 10 万就要警惕 dict 开销
如何限制输出缓冲区防止消息积压撑爆内存?
这是最直接有效的干预点。Redis 允许为 Pub/Sub 连接单独设缓冲区上限,超出即断连,避免单个慢消费者拖垮整个实例。
在 redis.conf 中配置:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
client-output-buffer-limit pubsub 32mb 8mb 60
含义:
-
32mb:硬上限,缓冲区一到 32MB 立刻踢掉连接 -
8mb:软上限,缓冲区持续 ≥8MB 超过 60 秒就踢 - 别设成
0或过大值(如512mb),否则失去保护意义
注意:该配置对已存在的连接不生效,需重启或 CONFIG REWRITE 后新连接才生效。
频道名怎么缩才既省内存又不翻车?
频道名不是字符串常量,而是被 Redis 用 dict 存储的 key,长度直接影响哈希桶和字符串内存开销。但缩写不能只图短。
安全缩写原则:
- 前缀必须可区分业务域,比如
ord:st:123(订单状态)和pay:st:123(支付状态)不能都缩成o:s:123 - 用冒号
:分隔,比下划线_少占 1 字节(ASCII 编码) - 避免动态拼接长 ID,例如不用
user:1234567890123456789:notify,改用u:sha256("1234567890123456789")[0:6] - 上线前跑一次
redis-cli --scan --pattern "your:*" | wc -l,如果结果 >10 万,考虑按 ID 尾号分片(如ord:0:123~ord:9:123)
真正容易被忽略的是:频道元数据一旦写入,即使没人发过消息也不会自动清理;而布隆过滤器只能拦新订阅,对已存在的无效频道完全无感。所以治理重点永远是“控连接 + 压频道 + 限缓冲”,不是加模块。

















