RocketMQ 的高可用架构是保障消息系统稳定运行的关键。本文将深入探讨 RocketMQ 的主从复制、Dledger、多机房部署等高可用方案。
一、高可用架构概览
1.1 整体架构
graph TB
subgraph 可用区 A
NS1[NameServer 1]
B1M[Broker 1 Master]
B2M[Broker 2 Master]
end
subgraph 可用区 B
NS2[NameServer 2]
B1S[Broker 1 Slave]
B2S[Broker 2 Slave]
end
subgraph 客户端
P[Producer]
C[Consumer]
end
NS1 -.-> NS2
B1M -.->|同步复制 | B1S
B2M -.->|异步复制 | B2S
P --> NS1
P --> NS2
C --> NS1
C --> NS2
1.2 高可用特性
| 特性 | 说明 | 实现方式 |
|---|---|---|
| NameServer 高可用 | 无状态设计,多节点部署 | 客户端轮询 |
| Broker 高可用 | 主从复制,自动切换 | Master-Slave |
| 数据高可用 | 多副本存储 | 同步/异步复制 |
| 多机房容灾 | 跨机房部署 | 异地多活 |
二、主从复制
2.1 复制模式
同步复制:
sequenceDiagram
participant P as Producer
participant M as Master
participant S as Slave
P->>M: 发送消息
M->>S: 同步消息
S-->>M: 确认
M-->>P: 返回成功
note over M,S: 数据强一致
# Broker Master 配置
brokerRole=SYNC_MASTER
flushDiskType=SYNC_FLUSH
# Broker Slave 配置
brokerRole=SLAVE
异步复制:
sequenceDiagram
participant P as Producer
participant M as Master
participant S as Slave
P->>M: 发送消息
M-->>P: 返回成功
M->>S: 异步同步消息
note over M,S: 数据最终一致
# Broker Master 配置
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
# Broker Slave 配置
brokerRole=SLAVE
2.2 配置示例
Master 配置:
# broker-a.properties
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0 # 0 表示 Master
namesrvAddr=ns1:9876;ns2:9876
# 复制模式
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
# 存储路径
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/commitlog
# 监听端口
listenPort=10911
Slave 配置:
# broker-a-s.properties
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=1 # >0 表示 Slave
namesrvAddr=ns1:9876;ns2:9876
# 从节点
brokerRole=SLAVE
# Master 地址
brokerIP1=192.168.1.100 # Master IP
masterAddress=192.168.1.100:10911
# 存储路径
storePathRootDir=/data/rocketmq/store-slave
2.3 故障切换
自动切换流程:
sequenceDiagram
participant P as Producer
participant NS as NameServer
participant M as Master
participant S as Slave
M --> M: 正常运行
P->>M: 发送消息
M --> M: 宕机
NS->>NS: 检测到 Broker 下线
NS->>P: 更新路由信息
P->>S: 发送到 Slave(只读)
note over P,S: 等待 Master 恢复
M->>M: 恢复启动
NS->>NS: 更新路由信息
P->>M: 恢复正常发送
手动切换:
#!/bin/bash
# 主从切换脚本
MASTER="broker-1"
SLAVE="broker-1-slave"
# 1. 停止 Master
echo "停止 Master..."
ssh $MASTER "systemctl stop rocketmq-broker"
# 2. 提升 Slave 为 Master
# 修改 Slave 配置
ssh $SLAVE "sed -i 's/brokerRole=SLAVE/brokerRole=ASYNC_MASTER/' /opt/rocketmq/conf/broker.conf"
ssh $SLAVE "sed -i 's/brokerId=1/brokerId=0/' /opt/rocketmq/conf/broker.conf"
# 3. 重启 Broker
ssh $SLAVE "systemctl restart rocketmq-broker"
# 4. 验证
mqadmin brokerStatus -n ns1:9876 -b $SLAVE:10911
# 5. 发送告警
sendAlert "Broker 主从切换完成:$MASTER -> $SLAVE"
三、Dledger 高可用
3.1 Dledger 架构
graph TB
subgraph Dledger Group
B1[Broker 1<br/>Leader]
B2[Broker 2<br/>Follower]
B3[Broker 3<br/>Follower]
end
P[Producer] --> B1
C[Consumer] --> B1
B1 -.->|Raft 复制 | B2
B1 -.->|Raft 复制 | B3
3.2 Dledger 配置
Broker 1 配置:
# broker-dledger-1.properties
brokerClusterName=DefaultCluster
brokerName=dledger-cluster
# Dledger 配置
enableDLegerCommitLog=true
dLegerGroup=dledger-cluster
dLegerPeers=n0-192.168.1.101:9878;n1-192.168.1.102:9878;n2-192.168.1.103:9878
dLegerSelfId=n0
# 存储路径
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/dledger
# 监听端口
listenPort=10911
Broker 2 配置:
# broker-dledger-2.properties
brokerClusterName=DefaultCluster
brokerName=dledger-cluster
# Dledger 配置
enableDLegerCommitLog=true
dLegerGroup=dledger-cluster
dLegerPeers=n0-192.168.1.101:9878;n1-192.168.1.102:9878;n2-192.168.1.103:9878
dLegerSelfId=n1
# 存储路径
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/dledger
# 监听端口
listenPort=10912
Broker 3 配置:
# broker-dledger-3.properties
brokerClusterName=DefaultCluster
brokerName=dledger-cluster
# Dledger 配置
enableDLegerCommitLog=true
dLegerGroup=dledger-cluster
dLegerPeers=n0-192.168.1.101:9878;n1-192.168.1.102:9878;n2-192.168.1.103:9878
dLegerSelfId=n2
# 存储路径
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/dledger
# 监听端口
listenPort=10913
3.3 Leader 选举
选举流程:
sequenceDiagram
participant B1 as Broker 1
participant B2 as Broker 2
participant B3 as Broker 3
B1->>B2: 请求投票
B1->>B3: 请求投票
B2-->>B1: 投票
B3-->>B1: 投票
B1->>B1: 成为 Leader
B1->>B2: 心跳
B1->>B3: 心跳
B1 --> B1: 宕机
B2->>B3: 请求投票
B3-->>B2: 投票
B2->>B2: 成为新 Leader
3.4 优缺点对比
| 特性 | 主从模式 | Dledger 模式 |
|---|---|---|
| 一致性 | 最终一致(异步) | 强一致(Raft) |
| 可用性 | 高 | 高 |
| 故障切换 | 手动/半自动 | 自动 |
| 部署复杂度 | 低 | 中 |
| 性能 | 高 | 中 |
| 适用场景 | 一般业务 | 金融场景 |
四、多机房部署
4.1 同城双活
graph TB
subgraph 机房 A
NS1[NameServer 1]
B1M[Broker 1 Master]
B2M[Broker 2 Master]
end
subgraph 机房 B
NS2[NameServer 2]
B1S[Broker 1 Slave]
B2S[Broker 2 Slave]
end
NS1 -.-> NS2
B1M -.-> B1S
B2M -.-> B2S
P[Producer] --> NS1
P --> NS2
配置要点:
# 机房 A Broker 配置
brokerClusterName=DefaultCluster
brokerId=0
brokerRole=ASYNC_MASTER
# 机房 B Broker 配置
brokerClusterName=DefaultCluster
brokerId=1
brokerRole=SLAVE
masterAddress=192.168.1.100:10911 # 机房 A Master
4.2 异地多活
graph TB
subgraph 北京机房
NS1[NameServer 1]
B1M[Broker 1 Master]
end
subgraph 上海机房
NS2[NameServer 2]
B1S[Broker 1 Slave]
end
subgraph 广州机房
NS3[NameServer 3]
B2M[Broker 2 Master]
end
NS1 -.-> NS2
NS2 -.-> NS3
B1M -.->|异地复制 | B1S
配置要点:
# 异地复制配置
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
flushSlaveTimeoutMillis=5000 # 增加超时时间
# 网络优化
sendHeartbeatTimeoutMillis=2000
clientChannelMaxIdleTimeSeconds=120
4.3 流量调度
DNS 调度:
# DNS 配置
rocketmq.example.com A 北京 IP
rocketmq.example.com A 上海 IP
rocketmq.example.com A 广州 IP
# 基于地理位置解析
北京用户 -> 北京机房
上海用户 -> 上海机房
广州用户 -> 广州机房
客户端配置:
// 多 NameServer 配置
producer.setNamesrvAddr("bj-ns:9876;sh-ns:9876;gz-ns:9876");
// 故障自动切换
producer.setRetryTimesWhenSendFailed(3);
producer.setRetryAnotherBrokerWhenNotStoreOK(true);
五、容灾演练
5.1 演练场景
| 场景 | 预期结果 | 恢复时间 |
|---|---|---|
| Broker 宕机 | Slave 接管,数据不丢失 | < 30 秒 |
| 机房故障 | 流量切换到备用机房 | < 1 分钟 |
| NameServer 故障 | 客户端自动切换 | < 10 秒 |
| 网络分区 | 数据一致,服务可用 | 自动恢复 |
5.2 演练步骤
#!/bin/bash
# 容灾演练脚本
echo "=== RocketMQ 容灾演练 ==="
echo "时间:$(date)"
# 1. 模拟 Broker Master 宕机
echo -e "\n=== 步骤 1: 停止 Master ==="
ssh broker-1 "systemctl stop rocketmq-broker"
echo "Master 已停止"
# 2. 验证 Slave 接管
echo -e "\n=== 步骤 2: 验证 Slave 接管 ==="
sleep 10
mqadmin brokerStatus -n ns1:9876 -b broker-1-slave:10911
# 3. 验证生产消费
echo -e "\n=== 步骤 3: 验证生产消费 ==="
producer.sh -n ns1:9876 -t test-topic -m 100
consumer.sh -n ns1:9876 -t test-topic -g test-group
# 4. 恢复 Master
echo -e "\n=== 步骤 4: 恢复 Master ==="
ssh broker-1 "systemctl start rocketmq-broker"
sleep 30
# 5. 验证集群状态
echo -e "\n=== 步骤 5: 验证集群状态 ==="
mqadmin clusterList -n ns1:9876
echo -e "\n=== 演练完成 ==="
5.3 演练报告
# 容灾演练报告
## 演练信息
- 时间:2026-06-10 14:00-15:00
- 参与人员:运维团队、开发团队
- 演练场景:Broker Master 宕机
## 演练过程
1. 14:00 停止 Broker-1 Master
2. 14:00:30 Slave 自动接管
3. 14:01:00 验证生产消费正常
4. 14:30 恢复 Master
5. 14:30:30 集群恢复正常
## 演练结果
- ✅ Slave 在 30 秒内接管
- ✅ 数据无丢失
- ✅ 生产消费影响 < 1 分钟
## 改进建议
1. 优化监控告警响应时间
2. 完善应急预案文档
3. 增加自动化切换脚本
六、监控告警
6.1 关键指标
| 指标 | 告警阈值 | 说明 |
|---|---|---|
| Broker 在线数 | < 预期数 | 节点宕机 |
| 主从同步延迟 | > 1000ms | 同步异常 |
| CommitLog 磁盘 | > 80% | 磁盘不足 |
| 消费堆积 | > 10000 | 消费滞后 |
6.2 告警配置
groups:
- name: rocketmq-ha
rules:
- alert: RocketMQBrokerDown
expr: up{job="rocketmq-broker"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Broker 宕机:{{ $labels.instance }}"
- alert: RocketMQSlaveLag
expr: rocketmq_slave_lag > 1000
for: 5m
labels:
severity: warning
annotations:
summary: "主从同步延迟:{{ $value }}ms"
- alert: RocketMQDiskHigh
expr: rocketmq_commitlog_disk_ratio > 80
for: 5m
labels:
severity: warning
annotations:
summary: "磁盘使用率过高:{{ $value }}%"
七、最佳实践
7.1 部署建议
| 场景 | 副本数 | 复制方式 | 刷盘方式 |
|---|---|---|---|
| 开发环境 | 1 | - | 异步 |
| 测试环境 | 2 | 异步 | 异步 |
| 生产环境 | 2 | 异步 | 异步 |
| 金融场景 | 3 | 同步 | 同步 |
7.2 运维建议
- 定期演练:每季度进行一次故障演练
- 监控告警:配置关键指标告警
- 备份策略:定期备份元数据
- 升级方案:滚动升级,避免服务中断
总结
RocketMQ 高可用架构的核心要点:
- 主从复制:同步/异步复制,故障切换
- Dledger:Raft 协议,自动选举
- 多机房部署:同城双活、异地多活
- 容灾演练:定期演练、快速恢复
- 监控告警:关键指标、分级告警
核心要点:
- 根据场景选择复制方式
- 理解主从和 Dledger 的区别
- 多机房部署提高容灾能力
- 定期演练保障可用性
参考资料
- RocketMQ 高可用官方文档
- Dledger GitHub
- 《RocketMQ 技术内幕》第 11 章