3. 消息模型与 Topic 设计:Topic 与 Partition、分区策略、读写分离下的 Topic 规划原则

3.1 核心概念:Topic 与 Partition

在消息队列中,Topic(主题)是消息的逻辑分类,生产者将消息发送到特定 Topic,消费者从该 Topic 订阅并消费消息。Partition(分区)是 Topic 的物理分片,每个 Partition 是一个有序、不可变的消息序列,对应一个独立的存储文件(如 CommitLog + ConsumeQueue)。

Partition 是消息队列实现水平扩展与并行消费的基础。一个 Topic 可包含多个 Partition,分布在集群的不同 Broker 节点上。Partition 的数量决定了该 Topic 的最大并行处理能力。

维度 Topic Partition
逻辑层级 消息分类,业务概念 物理分片,存储单元
扩展性 不可直接扩展 可增加(需谨慎)
有序性 全局无序 分区内严格有序
并行度 受 Partition 数限制 决定消费并发上限
存储 逻辑元数据 独立物理文件
关键认知:在读写分离架构下,Partition 的 Leader 负责写入,Follower 负责读取。Partition 数量直接影响读写分离的负载均衡效果与故障恢复速度。

3.2 分区策略:消息如何分布到 Partition

分区策略决定了生产者将消息发送到哪个 Partition。常见的分区策略包括:

  • 轮询策略(Round-Robin):消息依次发送到每个 Partition,实现负载均衡。适用于无 key 消息,吞吐量高但无法保证顺序。
  • 哈希策略(Hash):根据消息 key(如订单 ID、用户 ID)计算哈希值,相同 key 的消息落入同一 Partition。保证局部有序,适用于状态机、事务日志等场景。
  • 自定义策略:实现 Partitioner 接口,按业务规则分配。例如按地域、按优先级、按数据量大小。
  • 粘性分区策略(Sticky Partitioner):批量发送时,将一批消息粘到同一个 Partition,减少网络连接开销。RocketMQ 5.x 默认使用此策略。
// RocketMQ 自定义分区器示例
public class OrderPartitioner implements MessageQueueSelector {
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        String orderId = (String) arg;
        int hash = Math.abs(orderId.hashCode());
        int index = hash % mqs.size();
        return mqs.get(index);
    }
}
压测建议:在读写分离场景下,哈希策略可能导致 Partition 数据倾斜(Hot Partition)。压测时需监控各 Partition 的写入 QPS 与存储水位,若偏差超过 20%,应调整分区策略或增加 Partition 数量。

3.3 读写分离下的 Topic 规划原则

在读写分离架构中,Topic 的规划直接影响系统性能与稳定性。以下是经过生产验证的规划原则:

  1. Partition 数量 = 集群 Broker 数 × 2~4
    保证每个 Broker 承载 2~4 个 Leader Partition,避免单点过热,同时为 Follower 预留足够副本。
  2. 副本因子 = 2~3
    读写分离要求至少 1 个 Leader + 1 个 Follower。副本数过多会增大写入延迟与存储开销。
  3. 避免 Topic 数量过多
    每个 Topic 的元数据与文件句柄占用资源。建议单集群 Topic 数不超过 1000,Partition 总数不超过 10000。
  4. 读写流量隔离
    将高写入 Topic 与高读取 Topic 分到不同 Broker 组,或使用不同 Topic 前缀进行物理隔离。
  5. Partition 扩容预留
    初始 Partition 数应预留 30%~50% 的扩容空间,避免后续扩容导致数据重分布影响在线业务。
场景 推荐 Partition 数 副本因子 说明
日志采集(高写入) 16~32 2 轮询策略,允许少量丢失
订单状态(高可靠) 8~16 3 哈希策略,保证顺序
实时推荐(高读取) 32~64 2 粘性分区,批量读取
金融交易(强一致) 4~8 3 自定义策略,同步刷盘
读写分离下 Topic 与 Partition 规划架构 生产者集群 Topic: OrderTopic Partition 总数: 12 Partition 物理分片(Broker 节点) Partition-0 Leader Partition-1 Follower Partition-2 Follower 消费者组 读写分离流量路径 • 写入路径:生产者 → Topic → Partition-0 (Leader) → 同步到 Follower • 读取路径:消费者 → Partition-1 (Follower) / Partition-2 (Follower) → 返回消息 • 原则:写入只走 Leader,读取优先走 Follower,降低 Leader 负载

3.4 分区策略选择矩阵

不同业务场景对分区策略的要求不同。以下矩阵帮助快速决策:

业务需求 推荐策略 优点 缺点 读写分离适配
全局吞吐量优先 轮询 / 粘性分区 负载均匀,无倾斜 无法保证顺序 高,Follower 读取均衡
局部顺序保证 哈希(按业务 key) 相同 key 顺序消费 可能数据倾斜 中,需监控倾斜
优先级调度 自定义(按优先级) 高优消息优先处理 实现复杂 低,Follower 可能滞后
地域亲和性 自定义(按地域 ID) 减少跨机房延迟 Partition 数需匹配地域数 高,Follower 就近读取
避坑提示:不要在生产环境中使用“随机策略”或“无策略”发送消息。这会导致 Partition 数据严重倾斜,部分 Partition 写入量是其他 Partition 的 10 倍以上,直接引发读写分离下的 Follower 读取延迟飙升。

3.5 读写分离下的 Topic 规划检查清单

  • Partition 数是否满足峰值吞吐? 压测时单 Partition 写入上限约 10~20 MB/s,读取上限约 30~50 MB/s。
  • 副本因子是否匹配可靠性要求? 读写分离至少需要 2 副本,金融场景建议 3 副本。
  • 是否有 Hot Partition? 使用哈希策略时,检查 key 分布是否均匀,必要时增加 Partition 数或改用粘性分区。
  • Topic 数量是否在合理范围? 单集群 Topic 数超过 1000 时,元数据同步与文件句柄开销显著增大。
  • 扩容方案是否就绪? 提前规划 Partition 扩容流程,包括数据迁移、消费者重平衡、流量切换。
Topic 规划决策流程 开始规划 Topic 峰值吞吐 > 单 Partition 上限? 需要局部顺序? 确定 Partition 数 + 分区策略

3.6 压测验证要点

在读写分离架构下,Topic 规划是否合理需要通过压测验证:

  • 写入压测: 使用轮询策略发送 100 万条消息,监控各 Partition 的写入 QPS 与延迟。若最大/最小 QPS 比值 > 1.5,说明分区策略或 Partition 数不合理。
  • 读取压测: 从 Follower Partition 读取消息,对比 Leader 与 Follower 的读取延迟。若 Follower 延迟 > Leader 延迟 2 倍,说明副本同步存在瓶颈。
  • 故障模拟: 手动停止一个 Broker,观察消费者重平衡时间与消息堆积情况。重平衡时间应 < 30 秒,堆积消息应在 5 分钟内消费完毕。
专家建议:在压测报告中,除了常规的吞吐量与延迟指标,务必包含“Partition 倾斜度”与“副本同步滞后量”两个指标。这两个指标是读写分离架构健康度的核心晴雨表。