redis 7 pub/sub带宽突增主因是消息体积×频率×订阅数叠加导致网卡出口打满,需用iftop -p 6379和redis-cli --stat查net_input/output_bytes验证,而非依赖instantaneous_ops_per_sec。

Redis 7 中发布订阅引发的带宽突增,基本不是 Redis 自身卡顿或配置错误,而是消息体积 × 频率 × 订阅数在网卡出口上直接堆出来的流量。先算再查,别一上来就调参。
怎么快速确认是不是 Pub/Sub 在吃带宽
别依赖 redis-cli info stats 里的 instantaneous_ops_per_sec——它只统计命令数,不反映字节量。真实压力在网卡上:
- 在 Redis 服务器上跑
iftop -P 6379,盯住TX(上行)和RX(下行)实时速率,看是否贴近网卡上限(比如云主机标称 5 Mbps 上行,实测持续 4.8 Mbps 就得警觉) - 用
redis-cli --stat观察net_input_bytes和net_output_bytes每秒增量,单位是字节;乘以 8 换算成 bit,就是实际带宽占用 - 执行
PUBSUB NUMSUB your_channel确认当前活跃订阅数,再结合你已知的PUBLISHQPS 和消息平均大小,手动验算:「消息字节数 × QPS × 订阅数 × 1.12」是否匹配观测值
SPUBLISH 场景下带宽异常飙升的隐蔽原因
用了 Redis 7 的 SPUBLISH,不代表带宽就自动降下来。分片只解决“发给谁”,不解决“发多少”:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 如果所有消息都用同一个
shardkey(比如硬编码为"global"),那全部流量仍压在一个节点上,该节点的出口带宽照样打满 -
SSUBSCRIBE客户端若跨地域部署(如华东节点订阅、华北节点发布),消息虽只路由到目标分片,但跨机房链路仍要承载完整副本,延迟+丢包+带宽成本三重叠加 -
SPUBLISH不改变单条消息的协议开销,>4KB 的消息仍会触发 TCP 分段重传;实测中 10KB 消息在公网环境下 P99 延迟翻 20 倍,重传导致有效吞吐暴跌
为什么监控看到带宽高,却找不到对应频道
常见错觉:PUBSUB NUMSUB 返回空或数字很小,但 net_output_bytes 却狂涨。这通常指向两个被忽略的路径:
- 模式订阅(
PSUBSCRIBE alert.*)没被PUBSUB命令统计,得用PUBSUB NUMPAT查数量;而每个匹配到的实际频道,都会独立广播一份消息,10 个匹配频道 = 10 倍带宽 - 客户端崩溃后未调用
UNSUBSCRIBE,Redis 仍维持连接并尝试投递,直到 TCP 超时(默认 2 小时)。用CLIENT LIST过滤cmd=subscribe状态的连接,看idle时间是否远超业务预期 - Sharded Pub/Sub 下,
PUBSUB命令对SSUBSCRIBE完全不可见,必须用SPUBSUB NUMSUB channel shardkey才能查到真实订阅数
压缩与限流:最直接有效的带宽控制手段
协议层和应用层双管齐下,比调 tcp-keepalive 或连接池参数更治本:
- 消息体强制走序列化压缩:JSON 改用
msgpack,文本内容启用zstd(比 gzip 快 3 倍,压缩率相当),实测可将 8KB 消息压到 1.2KB,带宽直降 85% - 服务端不做无差别广播:在网关层(而非 Redis 层)聚合同类事件,例如把 5 秒内 20 条订单状态变更合并为 1 条 delta 更新,QPS 降为 1/5,消息体反而更小
- 客户端侧加发送节流:Lettuce 用户可在
StatefulRedisPubSubConnection上设writeTimeout+ 重试退避,避免突发消息洪峰打穿网卡
真正难处理的是分片键设计与业务语义耦合太紧——比如用 user_id 分片保序,但某超级用户日均消息占集群总 Pub/Sub 流量 40%,此时压缩和限流都只是缓兵之计,得动数据模型。










