RocketMQ 有几种集群部署方式?
结论:官方给的是四种拓扑递进——单 Master、多 Master 无从、多 Master 多 Slave 异步复制、多 Master 多 Slave 同步双写;生产上一般用 2 主 2 从,交易链路选同步双写、一般业务选异步复制。5.x 又补了基于 Raft 的 DLedger 与控制器主备自动切换,把"主挂了要人工切"这个老问题补上了。
一、四种部署模式对比
| 模式 | 可用性 | 数据可靠性 | 主要问题 | 适用场景 |
|---|---|---|---|---|
| 单 Master | 最低 | 宕机即不可用 | 单点,重启期间不能收发 | 本地开发、压测 |
| 多 Master 无从 | 中 | 磁盘损坏就丢该节点数据 | 节点挂后其消息在恢复前无法消费 | 对可靠性要求低的内部系统 |
| 多 Master 多 Slave 异步 | 较高 | 主宕可能丢少量未同步消息 | 主从切换需人工或 5.x 控制器 | 大多数业务系统 |
| 多 Master 多 Slave 同步双写 | 高 | 主从都落盘才算成功 | 写 RT 上升约 10%~30%,主从任一异常即降级 | 支付、订单、账务 |
| DLedger(Raft) | 最高 | 多数派落盘,自动选主 | 部署成本高、吞吐略降 | 强一致、免人工运维 |
二、2 主 2 从异步复制的典型布局
NameServer A NameServer B
▲ ▲
心跳/注册 │ │ 心跳/注册
┌─────────┴───────────┬───────────┴─────────┐
│ │ │
┌──▼──────────┐ 同步/异步 ┌──────────────┐ │
│ broker-a(0) │ ─────────> │ broker-a(1) │ │
│ 主,读写 │ │ 从,只读 │ │
└──┬──────────┘ └──────────────┘ │
│ │
┌──▼──────────┐ 同步/异步 ┌──────────────┐ │
│ broker-b(0) │ ─────────> │ broker-b(1) │ │
└─────────────┘ └──────────────┘ │
│
同 brokerName、不同 brokerId 的两个节点互为主从
要点:brokerName 相同、brokerId 分别为 0 和 1 才构成主从关系;同一个 Topic 的队列会均摊到两个主节点,主从复制只发生在同名 broker 之间。
三、副本方式与刷盘方式的组合
| 复制方式 | 刷盘方式 | 组合效果 |
|---|---|---|
| 异步复制 | 异步刷盘 | 吞吐最高,宕机可能丢一批消息 |
| 异步复制 | 同步刷盘 | 单机掉电不丢,但主挂时未复制的部分会丢 |
| 同步双写 | 异步刷盘 | 主从都有数据,掉电靠页缓存刷盘兜底 |
| 同步双写 | 同步刷盘 | 最稳,RT 最高,仅账务类使用 |
注意:同步双写不等于同步刷盘。前者是等从节点写入成功,后者是等本机 fsync 成功,两者正交,不要混为一谈。
四、配置示例
# broker-a.properties(主)
brokerClusterName=OrderCluster
brokerName=broker-a
brokerId=0
brokerRole=SYNC_MASTER
flushDiskType=ASYNC_FLUSH
namesrvAddr=10.0.0.11:9876;10.0.0.12:9876
# broker-a-s.properties(从)
brokerClusterName=OrderCluster
brokerName=broker-a
brokerId=1
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
namesrvAddr=10.0.0.11:9876;10.0.0.12:9876
DLedger 模式则把角色交给 Raft,配置换成:
enableDLegerCommitLog=true
dLegerGroup=broker-a
dLegerPeers=n0-10.0.0.11:40911;n1-10.0.0.12:40911;n2-10.0.0.13:40911
dLegerSelfId=n0
五、常见追问
- 主节点挂了,4.x 能自动切换吗? 不能。4.x 的从节点只提供读,需要运维把从节点改成主或重启为
ASYNC_MASTER;5.x 增加了 Controller 组件,可自动选主。 - 同步双写会不会拖垮性能? 会抬高写延迟,但换来"主从都有数据"。折中做法是核心 Topic 同步双写、日志类 Topic 异步复制。
- 多 Master 无从为什么还能用? 因为每个主节点独立承担一部分队列,单节点挂掉只影响它上面那部分消息,其他节点照常读写;代价是故障期间这部分消息不可消费。
- 为什么主从必须同 brokerName? 路由以 brokerName 为单位,一个 brokerName 对应一组主从;消费者根据 brokerName 找到主节点拉消息。
小结
- 部署方式的选择本质是可用性、数据可靠性、写延迟三者的取舍。
- 生产标准配置是 2 主 2 从,交易类用同步双写,其余用异步复制。
- 4.x 主从切换靠人工或脚本,5.x 用 Controller / DLedger 实现自动选主。
- 复制方式与刷盘方式是两组正交开关,配置时要分别确认。