3. 消息模型与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 的规划直接影响系统性能与稳定性。以下是经过生产验证的规划原则:
- Partition 数量 = 集群 Broker 数 × 2~4
保证每个 Broker 承载 2~4 个 Leader Partition,避免单点过热,同时为 Follower 预留足够副本。 - 副本因子 = 2~3
读写分离要求至少 1 个 Leader + 1 个 Follower。副本数过多会增大写入延迟与存储开销。 - 避免 Topic 数量过多
每个 Topic 的元数据与文件句柄占用资源。建议单集群 Topic 数不超过 1000,Partition 总数不超过 10000。 - 读写流量隔离
将高写入 Topic 与高读取 Topic 分到不同 Broker 组,或使用不同 Topic 前缀进行物理隔离。 - Partition 扩容预留
初始 Partition 数应预留 30%~50% 的扩容空间,避免后续扩容导致数据重分布影响在线业务。
| 场景 | 推荐 Partition 数 | 副本因子 | 说明 |
|---|---|---|---|
| 日志采集(高写入) | 16~32 | 2 | 轮询策略,允许少量丢失 |
| 订单状态(高可靠) | 8~16 | 3 | 哈希策略,保证顺序 |
| 实时推荐(高读取) | 32~64 | 2 | 粘性分区,批量读取 |
| 金融交易(强一致) | 4~8 | 3 | 自定义策略,同步刷盘 |
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 扩容流程,包括数据迁移、消费者重平衡、流量切换。
3.6 压测验证要点
在读写分离架构下,Topic 规划是否合理需要通过压测验证:
- 写入压测: 使用轮询策略发送 100 万条消息,监控各 Partition 的写入 QPS 与延迟。若最大/最小 QPS 比值 > 1.5,说明分区策略或 Partition 数不合理。
- 读取压测: 从 Follower Partition 读取消息,对比 Leader 与 Follower 的读取延迟。若 Follower 延迟 > Leader 延迟 2 倍,说明副本同步存在瓶颈。
- 故障模拟: 手动停止一个 Broker,观察消费者重平衡时间与消息堆积情况。重平衡时间应 < 30 秒,堆积消息应在 5 分钟内消费完毕。
专家建议:在压测报告中,除了常规的吞吐量与延迟指标,务必包含“Partition 倾斜度”与“副本同步滞后量”两个指标。这两个指标是读写分离架构健康度的核心晴雨表。