sharded pub/sub 不是提升横向扩展力的万能补丁,而是专治 redis 集群中传统 pubsub 的连接爆炸、广播浪费和路由失效问题;它通过分片键实现真订阅,但要求业务能明确划分消息边界。

直接说结论:Sharded Pub/Sub 不是用来“提升横向扩展力”的万能补丁,而是专治集群模式下传统 PUBSUB 伪支持导致的连接爆炸、广播浪费和路由失效——它让发布订阅真正适配 Redis 集群的分片模型,但前提是你的业务能明确划分消息边界。
为什么传统 SUBSCRIBE 在集群里根本不算“真订阅”
Redis 6 及更早版本在集群中对 SUBSCRIBE 的支持是“本地有效、全局失效”:你连到节点 A 订阅 order:1001,只能收到发往节点 A 的消息;如果发布者连的是节点 B,且 order:1001 实际落在节点 C,那这条消息就丢了——PUBSUB CHANNELS 返回空,PUBLISH 也不报错,只是静默丢弃。
这不是 bug,是设计限制:传统频道没哈希槽绑定逻辑,服务端无法判断该把消息路由到哪。
常见错误现象包括:
- 客户端反复重连多个节点,手动维护 N 个连接分别
SUBSCRIBE - 部分订阅者收不到消息,日志里查不到失败记录
-
INFO pubsub显示订阅数为 0,但客户端坚称自己已订阅
SPUBLISH / SSUBSCRIBE 必须带分片键,否则直接报错
SPUBLISH 和 SSUBSCRIBE 不接受单参数调用。少传分片键,命令会立刻失败:
127.0.0.1:7000> SPUBLISH order:1001 "payload" (error) ERR wrong number of arguments for 'spublish' command
正确写法必须显式提供分片键(第二个参数),例如:
-
SPUBLISH order:1001 1001 "payload"—— 用用户 ID 作分片键,保序且路由稳定 -
SSUBSCRIBE order:1001—— 订阅时不用传键,服务端按频道名自动提取哈希槽
注意:order:1001 这个字符串本身不参与路由,真正决定目标节点的是你传的 1001 这个分片键。如果你传 SPUBLISH order:1001 abc "payload",那它会被路由到 abc 对应的槽位,和 1001 完全无关。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
客户端库不升级,新命令根本调不了
主流驱动如 jedis、lettuce 在 Redis 7.0 发布前不识别 SSUBSCRIBE 等命令,会直接抛 UnsupportedCommandException 或解析失败。
实操建议:
- 确认驱动版本 ≥ 对应 Redis 7.0 支持的最小版本(例如 Lettuce 6.3+)
- 检查 ACL 权限是否开放:
SPUBLISH和SSUBSCRIBE需要显式授权,旧 ACL 规则默认不包含 - 监控不再走
INFO pubsub,改查INFO cluster中的sharded_pubsub_channels和sharded_pubsub_clients
Spring Data Redis 的 reactive API 目前仍需手动封装命令,ReactiveRedisOperations 默认不提供 sSubscribe() 方法。
不是所有场景都适合迁移到 Sharded 模式
强行把广播类消息(比如系统公告、配置刷新)塞进 SPUBLISH,等于人为制造热点分片:所有消息都路由到同一个槽,失去水平扩展意义。
适用场景有明确共性:
- 消息天然具备强归属维度(用户 ID、设备 ID、订单号)
- 需要严格保序(同分片键下消息 FIFO)
- 订阅者数量随业务实体线性增长(如每个用户一个通知频道)
容易被忽略的关键点:分片键一旦选定就难以变更。比如用手机号做键,后期要支持国际号码格式变更,就会触发大量数据迁移或兼容逻辑——这比缓存 key 设计更敏感,因为路由逻辑固化在协议层。










