redis传统publish/subscribe在集群中引发广播风暴,因publish被转发至所有主节点;spublish强制分片键路由,ssubscribe与subscribe完全隔离,保序依赖分片键选择。

为什么传统 PUBLISH/SUBSCRIBE 在 Redis 集群里会广播风暴
在 Redis 6 及更早集群中,PUBLISH 命令不是发给某个节点,而是被客户端连接的节点**转发到所有主节点**——哪怕只有 1 个订阅者在节点 A,消息也会被复制到节点 B、C、D……每个节点都执行一次发布逻辑。这导致:带宽浪费、CPU 重复计算、消息重复投递风险、SUBSCRIBE 客户端收不到跨节点消息(因为只连了一个节点)。根本原因在于旧机制没分片语义,频道名不参与哈希路由。
SPUBLISH 必须带分片键,否则直接报错
SPUBLISH 不是 PUBLISH 的“增强版”,它是全新协议,强制要求三个参数:SPUBLISH <channel><shardkey><message></message></shardkey></channel>。漏掉 shardkey 就会返回 ERR wrong number of arguments。这个 shardkey 才是决定消息落到哪个槽、哪个节点的唯一依据,和 channel 名字完全无关。
- 正确写法:
SPUBLISH order:notify 1001 "order_created"(用用户 ID 作分片键) - 错误写法:
SPUBLISH order:notify "order_created"(少一个参数) - 错误写法:
SPUBLISH order:notify user:1001 "order_created"(shardkey是字符串"user:1001",但哈希值跟数字1001不同,可能路由错)
SSUBSCRIBE 和传统 SUBSCRIBE 不能混用
你不能在一个客户端上先 SUBSCRIBE ch1,再 SSUBSCRIBE ch1 1001;也不能让一部分服务用 PUBLISH,另一部分用 SPUBLISH。Sharded Pub/Sub 和传统 Pub/Sub 是两套完全隔离的通道:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 订阅
SSUBSCRIBE的客户端,只收得到SPUBLISH发出的消息 -
PUBSUB NUMSUB查不到SSUBSCRIBE的订阅数,得用SPUBSUB NUMSUB - 监控指标也分开:
instantaneous_ops_per_sec统计PUBLISH,而sharded_pubsub_channels等新字段才反映 Sharded 流量
分片键选型直接影响保序与扩展性
保序只在同一个 shardkey 下成立。比如你用订单 ID 作分片键,那所有该订单的事件(创建、支付、发货)一定按顺序到达;但不同订单之间互不影响。这就要求你提前判断业务约束:
- 要严格保序?选高基数、业务强关联字段,如
order_id、user_id - 要打散负载?避免用固定值(如
"global"),否则所有消息挤在一个节点 - 要兼容老逻辑?不能把
shardkey写死成常量,否则失去分片意义,退化成单点瓶颈
真正容易被忽略的是:分片键一旦选定,就很难动态变更。它决定了数据物理分布,改了就得迁移客户端逻辑+重连+清空旧频道状态——不是改个配置就能切的。










