Redis 7.0 通过 Sharded Pub/Sub 解决集群广播瓶颈:按 channel 哈希路由至目标节点,仅在该节点发布与投递,避免全集群广播,需显式启用 SSUBSCRIBE/SPUBLISH 并配置 shard-subscribe-enabled yes。

Redis Cluster 中 PUBLISH 触发全节点广播
在 Redis 7.0 之前,集群模式下 PUBLISH 命令不是发给某个 slot 对应的节点,而是由接收命令的节点向**所有其他节点广播**该消息。哪怕只有一个客户端在节点 A 上订阅了 ch:order:123,只要有人在任意节点执行 PUBLISH ch:order:123 "data",这条消息就会被复制并发送到全部节点——包括那些压根没订阅该 channel 的节点。
常见错误现象:
- 集群规模从 3 节点扩到 9 节点后,
PUBLISH吞吐反而下降 50%+ -
redis-cli --stat显示net_input_bytes突增数倍,但pubsub_channels数量几乎不变 - 某节点 CPU 使用率持续 90%+,
top -H查看发现多个redis-server线程在忙于处理publish相关 I/O
为什么不能按 slot 路由?
旧版集群没有为 Pub/Sub 建立 channel 到 slot 的映射规则。Redis 的 slot 分配只作用于 key(如 SET user:1001 ...),而 PUBLISH 的 channel 不是 key,不参与 CRC16 计算,也不绑定任何 slot。所以系统无法判断“ch:notify:alarm”该落在哪个分片上,只能退化为全量转发。
这导致两个根本限制:
-
SUBSCRIBE是本地行为:每个节点只维护自己收到的SUBSCRIBE请求,不会同步给其他节点 - 没有全局订阅状态视图:节点 A 不知道节点 B 是否有客户端订阅了
ch:log,只能全发、让对方自行丢弃
带宽与 CPU 消耗随节点数线性增长
假设单条消息平均 200 字节,集群有 N 个节点,每秒发布 M 条消息,则网络总开销是 N × (N−1) × M × 200 字节/秒——因为每个节点都要向其余 N−1 个节点各发一份。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
实测数据(Redis 6.2,6 节点集群):
- 100 QPS
PUBLISH→ 单节点出向流量 ≈ 1.2 MB/s - 500 QPS
PUBLISH→ 出向流量跃升至 ≈ 5.8 MB/s,且出现timeout和消息延迟 >200ms - 同一配置下启用
io-threads 4并不能缓解,因为多线程只加速本节点读写,不减少跨节点冗余流量
升级到 Redis 7.0 后仍走旧路径?
关键点在于:SUBSCRIBE 和 PUBLISH 命令本身**完全不感知集群分片逻辑**。即使你用的是 Redis 7.0 集群,只要客户端还在调用 SUBSCRIBE,服务端就继续走全广播路径。
必须显式切换才能生效:
- 订阅必须改用
SSUBSCRIBE(sharded subscribe) - 发布必须改用
SPUBLISH(sharded publish) - 服务端需开启配置项:
shard-subscribe-enabled yes - 客户端 SDK 必须支持——比如
redis-py ≥ 4.6.0才提供ssubscribe()方法
最容易被忽略的一点:通配符订阅 PSUBSCRIBE 在 Sharded 模式下直接不可用,因为它无法预计算匹配哪些 channel 对应哪些 slot。如果你的应用依赖模糊匹配,就得重构为显式 channel + 多个 SSUBSCRIBE,或者换用 Stream。

















