redis 7.0的sharded pub/sub是专为集群设计的新协议,不兼容传统pub/sub,需用spublish/ssubscribe并强制指定分片键路由消息,保序性仅限同分片键内,客户端、acl、监控均需适配。

Redis 7.0 的 Sharded Pub/Sub 不是传统 Pub/Sub 的“升级版”,而是专为集群设计的一套全新协议——不兼容 SUBSCRIBE、PUBLISH,也不能靠改配置或换客户端库自动生效。想在集群里用好它,必须从命令、分片键、客户端调用三方面重写逻辑。
SPUBLISH 和 SSUBSCRIBE 必须带分片键,否则直接报错
旧代码里 PUBLISH chat:room:123 "hi" 换成 SPUBLISH chat:room:123 "hi" 会失败,因为 SPUBLISH 至少需要三个参数:SPUBLISH <channel><shard-key><message></message></shard-key></channel>。第二个参数 <shard-key></shard-key> 才决定消息路由到哪个节点。
-
SPUBLISH order:1001 1001 "paid":以1001为分片键,消息只会发给负责 slotCLUSTER KEYSLOT("1001")的节点 -
SSUBSCRIBE order:1001 1001:同样传入1001,订阅者才连到同一节点,才能收到上面那条消息 - 如果
shard-key是空字符串或缺失,Redis 返回ERR wrong number of arguments - 频道名(第一个参数)本身不参与哈希计算,只是语义标识;真正路由依据只有
shard-key
分片键选错会导致消息丢失或乱序
Sharded Pub/Sub 的保序性只在**同分片键内**成立。比如你用用户 ID 做分片键,那所有属于该用户的事件(登录、下单、退款)会严格按时间顺序到达;但不同用户之间无顺序保证。选错键,就等于把本该串行处理的消息打散到多个节点上。
- 适合场景:按业务实体隔离,如
user_id、order_id、tenant_id - 不适合场景:全局广播类消息(如系统公告),这类消息天然不需要保序,也不该走 Sharded 模式
- 避免用随机数、时间戳、UUID 做分片键——会导致消息均匀打散,失去局部性,也丧失保序价值
- 若需多维度路由(如按地区+用户),应拼接成确定字符串,例如
"shenzhen:1001",确保相同组合总映射到同一 slot
客户端必须显式支持新命令,老驱动默认不识别
主流客户端库在 Redis 7.0 之前版本根本不认识 SSUBSCRIBE 或 SPUBLISH。即使你服务端是 7.0,客户端发过去也会被当成未知命令拒绝。
-
redis-py需 ≥ 4.6.0;调用方式不是r.publish(),而是r.execute_command("SPUBLISH", channel, shard_key, msg) -
Lettuce需 ≥ 6.3.0;提供StatefulRedisConnection.sSubscribe()等封装方法 -
Jedis需 ≥ 4.4.0;使用jedis.ssubscribe(),注意不是subscribe() - ACL 权限也要单独开通:
ACL SETUSER myuser +@pubsub +s*(+s*是允许所有 sharded 命令)
监控和调试不能依赖 info pubsub
传统 INFO PUBSUB 输出完全不包含 Sharded 流量,查不到活跃频道数、订阅者数量。要用专门的 cluster 子命令。
- 查当前活跃的分片频道:
PUBSUB SHARDCHANNELS(支持 pattern,如PUBSUB SHARDCHANNELS "order:*") - 查某频道订阅人数:
PUBSUB SHARDNUMSUB order:1001,返回格式类似1) "order:1001" 2) (integer) 3 - 集群整体指标看
INFO CLUSTER中的sharded_pubsub_channels、sharded_pubsub_clients字段 - 连接断开后不会自动重连——
SSUBSCRIBE是普通 TCP 连接,客户端要自己实现重连+重订阅逻辑
最容易被忽略的是:Sharded Pub/Sub 的“分片键”不是可选优化项,而是强制路由依据;它让消息不再广播,但也彻底放弃了跨节点语义。如果你的业务模型天然需要一对多广播(比如通知所有在线客服),那就别硬套这个机制——要么退回到单节点/哨兵部署跑传统 Pub/Sub,要么自己在应用层做 fan-out。











