pubsub_channels指标暴涨说明频道名动态生成未收敛,导致跳表索引膨胀、匹配开销增大,并引发订阅者输出缓冲区(omem)连锁堆积,最终触发oom;需结合pubsub numsub、client list omem及频道前缀分布定位根因。

pubsub_channels指标暴涨说明什么
当PUBSUB CHANNELS返回的频道数远超业务预期(比如从几十个突然跳到上万个),基本可以断定是频道名被动态生成且未收敛,典型如用user:12345:timestamp或order:uuid4()这类不可复用的字符串做频道名。Redis内部用跳表维护频道索引,频道越多,每次PUBLISH前的匹配开销越大——这不是CPU问题,而是内存和时间双线性增长:每个频道都要在跳表里存一份指针,还要为每个订阅者复制消息到其输出缓冲区。
为什么高频道数会触发OOM而不是单纯卡顿
频道本身不占多少内存,但每个频道背后可能挂载大量订阅客户端;而每个订阅客户端的输出缓冲区(omem)是独立分配的。一旦频道爆炸,又叠加消费延迟,就会出现“一个频道→N个慢订阅者→N个持续膨胀的omem”的连锁反应。此时INFO memory里used_memory会飙升,但used_memory_dataset几乎不变——这些内存全在连接上下文里,不受maxmemory和淘汰策略约束。
-
PUBSUB NUMPAT值也同步异常高,说明还混入了大量PSUBSCRIBE正则模式订阅,进一步放大匹配成本 -
client_longest_output_list持续 > 5000,意味着至少有一个客户端的输出链表已堆积数千条未发消息 -
mem_clients_pubsub在INFO memory中占比超过25%,是Pub/Sub内存失控的直接证据
怎么用PUBSUB CHANNELS快速定位问题频道
别直接跑PUBSUB CHANNELS *——它会阻塞主线程,尤其频道数过万时。正确做法是分批采样+结合业务特征过滤:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 先用
PUBSUB CHANNELS news*、PUBSUB CHANNELS user:*等带前缀的命令试探高频命名空间 - 对疑似前缀,用
redis-cli --scan --pattern "user:*" | head -n 1000 | sort | uniq -c | sort -nr | head -10查实际key分布(如果业务把频道名也当key用了) - 重点盯
PUBSUB NUMSUB channel_name返回为0的频道:长期无人订阅却持续存在,大概率是客户端订阅后没调UNSUBSCRIBE就断连,Redis不会自动清理空频道
监控pubsub_channels不能只看单点数值
PUBSUB CHANNELS本身是O(N)复杂度命令,频繁调用反而加重负担。生产环境应该:
- 用
redis-cli --stat配合--interval 10每10秒采一次INFO clients里的connected_clients和client_longest_output_list,比轮询频道更轻量 - 把
PUBSUB CHANNELS结果接入巡检脚本,只在凌晨低峰期全量执行,并告警突增>300%的频道前缀 - 真正关键的是联动看
CLIENT LIST输出里的omem字段:频道数多不可怕,可怕的是频道多+单个omem> 10MB的客户端扎堆出现
频道名设计没收敛、客户端不主动退订、缓冲区限制没配硬限——这三件事凑一起,PUBSUB CHANNELS数字只是表象,OOM才是必然结果。










