登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis 分片发布订阅怎样选择频道

来源:17golang原创

时间:2026-10-17 22:44:13 232浏览 收藏

Redis Cluster 里的频道选择,关键不在于“有没有集群”,而在于一条消息究竟要广播给谁。如果每个节点上的订阅者都应该收到消息,继续用普通 SUBSCRIBE 与 PUBLISH;如果消息只属于某个业务分区,希望传播限制在一个 shard 内,再用 Redis 7.0+ 的 SSUBSCRIBE 与 SPUBLISH。频道名要能把业务分区表达出来,否则分片能力很难发挥。

官方文档:https://redis.io/docs/latest/

先按广播范围选命令,再按频道名看分布:全局通知用普通 Pub/Sub,分区事件用分片 Pub/Sub。两者都只把消息交给当时在线的订阅者,不能拿来替代需要持久化、重放或确认的队列。

先按广播范围选择命令

普通 Pub/Sub 的语义是频道级广播。发布者调用 PUBLISH 后,订阅该普通频道的客户端都可能收到消息;在 Redis Cluster 中,普通 Pub/Sub 的消息需要在集群节点之间传播。它适合缓存失效、配置刷新、全站通知这类“所有相关实例都要知道”的事件。

分片 Pub/Sub 把频道按与 Redis 键相同的算法映射到槽位,消息在所属 shard 内传播。命令必须成对使用:发布侧用 SPUBLISH,消费侧用 SSUBSCRIBE。这不是把普通频道加了一个参数,而是另一套频道类型。

Redis 普通 Pub/Sub 与分片 Pub/Sub 的命令和 Cluster shard 边界静态结构图
图1:普通频道与分片频道的命令边界说明图,不是截图或运行证据。
判断维度普通 Pub/Sub分片 Pub/Sub
命令SUBSCRIBE、PUBLISHSSUBSCRIBE、SPUBLISH
广播边界面向全局 Pub/Sub 上下文限制在频道所属 shard
频道能力可用 PSUBSCRIBE 做模式订阅使用明确的分片频道,不要把普通模式订阅语义混进来
适合场景全局失效、配置刷新、站内通知租户、房间、分区或局部实时事件

让发布和订阅使用同一套频道语义

线上最容易出现的错误,是发布者改成了 SPUBLISH,消费者还在执行 SUBSCRIBE;或者消费者使用了 SSUBSCRIBE,发布者却仍然调用 PUBLISH。频道名字相同也不能抵消命令语义的差异。

可以先在配置中明确消息域,再把命令写死在同一条链路里。下面的命令只是说明用法,不是运行截图。普通频道和分片频道使用不同前缀,能让代码审查时更快发现混用。

# 普通 Pub/Sub:全局配置刷新,发布和订阅必须使用同一类频道
redis-cli SUBSCRIBE global:config:refresh
redis-cli PUBLISH global:config:refresh '{"version":42}'

# 分片 Pub/Sub:只让 tenant-42 的实时事件留在对应 shard
redis-cli SSUBSCRIBE tenant:42:events
redis-cli SPUBLISH tenant:42:events '{"type":"order.updated"}'

如果使用 Cluster 客户端,发布分片频道时应让客户端把请求路由到该频道槽位的节点;Redis 官方命令说明要求 SPUBLISH 发送到拥有该槽位的节点。订阅者则可以连接到该 shard 的主节点或副本节点订阅同一分片频道,具体路由交给支持 Cluster 的客户端库。

频道名决定分布,别让所有消息挤到一个 shard

分片频道的价值来自分布,而不是把 shard 这个词写进频道名。频道会按名称计算槽位,所以应把稳定的业务分区放进名称,让不同租户、房间或区域拥有多个频道。不要把所有业务事件都压成一个 events,那样订阅和发布仍可能集中在单个槽位。

频道设计可以遵循三个约束:

  • 前缀表达消息域,例如 tenant:、room: 或 region:,方便排查。
  • 分区标识使用稳定值,不要把随机请求 ID 当作频道,否则订阅管理会变得不可控。
  • 热点分区要单独评估,一个超级租户即使独占频道,也可能把单个 shard 推成瓶颈。
Redis 分片频道名称、槽位、发布节点和订阅节点的静态关系图
图2:分片频道从命名到 shard 归属的关系说明图,不是截图或运行证据。

这里不需要把频道名当成数据存储键来管理。Pub/Sub 没有键空间,KEYS 和 SCAN 看不到订阅频道;频道状态应通过 Pub/Sub 专用命令观察。

用专用命令检查订阅面和热点

普通频道和分片频道分别有对应的观察命令。检查时先确认你查看的是正确的上下文,尤其要记住 Cluster 下普通 PUBSUB 的返回只反映当前节点的 Pub/Sub 上下文,不等于全局汇总。

# 查看当前节点上下文里的普通频道和普通频道订阅数
redis-cli PUBSUB CHANNELS 'global:*'
redis-cli PUBSUB NUMSUB global:config:refresh

# 查看分片频道和分片频道订阅数
redis-cli PUBSUB SHARDCHANNELS 'tenant:*'
redis-cli PUBSUB SHARDNUMSUB tenant:42:events

如果业务只有一个全局频道、所有实例都必须接收,普通 Pub/Sub 更容易理解;如果频道按租户或房间拆开,并且各消费者只关心自己的分区,分片命令通常更贴合拓扑。观察时重点看频道数量、订阅数量和热点是否集中,而不是只看某一次发布返回的客户端数。

别把分片 Pub/Sub 当成可靠队列

普通和分片 Pub/Sub 都是实时传输:订阅者断线期间发布的消息不会自动补发。发布返回的计数也只说明当前命令触达的订阅客户端数量,不能证明消息已经落盘、被业务处理或可以重放。

因此可以把 Pub/Sub 放在“即时通知”一层,把真正需要可靠处理的数据先写入普通 Redis 键、数据库或 Streams。消费者重连后先根据持久化状态做一次对账,再恢复订阅;不要依靠频道本身恢复断线期间的事件。

最后可以按这张清单定案:

你的问题选择
所有集群节点上的相关订阅者都要收到吗?普通 SUBSCRIBE / PUBLISH
消息只属于一个租户、房间或业务分区吗?Redis 7.0+ 分片 SSUBSCRIBE / SPUBLISH
需要模式订阅吗?优先普通 Pub/Sub 的 PSUBSCRIBE,重新评估分片设计
断线后必须补齐消息吗?增加持久化记录或改用具备消费状态的消息模型

相关问题

Redis 分片频道能和普通频道混用吗?

同一个业务链路里最好不要混用。普通频道由 SUBSCRIBE/PUBLISH 管理,分片频道由 SSUBSCRIBE/SPUBLISH 管理;把频道前缀和客户端配置一起区分,能减少误发和漏收。

频道名应该按什么维度拆分?

按消费者真正关心的稳定分区拆分,例如租户、房间或区域。拆得太少会形成热点,拆得太碎又会增加订阅管理成本,最终应结合订阅数量和分区访问分布调整。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>