RocketMQ DLedger 是基于 Raft 协议的高可用存储方案,提供自动主从切换、强一致性保证。本文将深入探讨 DLedger 的原理、配置和实战。
一、DLedger 架构
1.1 架构演进
主从模式:
graph TB
subgraph Broker 集群
M[Master]
S1[Slave 1]
S2[Slave 2]
end
M -->|同步复制 | S1
M -->|同步复制 | S2
P[Producer] --> M
C[Consumer] --> M
DLedger 模式:
graph TB
subgraph DLedger Group
L[Leader]
F1[Follower 1]
F2[Follower 2]
end
L -.->|Raft | F1
L -.->|Raft | F2
P[Producer] --> L
C[Consumer] --> L
1.2 核心优势
| 优势 | 说明 |
|---|---|
| 自动切换 | Leader 宕机自动选举 |
| 强一致性 | Raft 协议保证 |
| 数据可靠 | 多数派确认 |
| 运维简单 | 无需手动切换 |
1.3 模式对比
| 特性 | 主从模式 | DLedger 模式 |
|---|---|---|
| 切换 | 手动/半自动 | 自动 |
| 一致性 | 最终一致 | 强一致 |
| 可靠性 | 中 | 高 |
| 性能 | 高 | 中 |
| 适用场景 | 一般业务 | 金融场景 |
二、Raft 协议
2.1 Raft 基础
Raft 协议核心:
1. Leader 选举
2. 日志复制
3. 安全性保证
2.2 Leader 选举
sequenceDiagram
participant N1 as Node 1
participant N2 as Node 2
participant N3 as Node 3
N1->>N1: 启动,成为 Follower
N2->>N2: 启动,成为 Follower
N3->>N3: 启动,成为 Follower
N1->>N2: Request Vote (Term 1)
N1->>N3: Request Vote (Term 1)
N2-->>N1: Vote Yes
N3-->>N1: Vote Yes
N1->>N1: 成为 Leader
N1->>N2: 心跳
N1->>N3: 心跳
2.3 日志复制
graph TB
subgraph Leader
L1[日志条目 1]
L2[日志条目 2]
L3[日志条目 3]
end
subgraph Follower 1
F1[日志条目 1]
F2[日志条目 2]
end
subgraph Follower 2
FF1[日志条目 1]
FF2[日志条目 2]
FF3[日志条目 3]
end
L1 --> F1
L1 --> FF1
L2 --> F2
L2 --> FF2
L3 --> FF3
三、DLedger 配置
3.1 Broker 配置
# broker.conf
# 启用 DLedger
enableDLegerCommitLog=true
# DLedger 组名
dLegerGroup=DefaultDledgerGroup
# DLedger 节点配置
dLegerPeers=n0-192.168.1.10:9878;n1-192.168.1.11:9878;n2-192.168.1.12:9878
# 当前节点 ID
dLegerSelfId=n0
# 存储路径
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/dledger
# 监听端口
listenPort=10911
3.2 多节点配置
节点 0:
# broker-n0.conf
enableDLegerCommitLog=true
dLegerGroup=DefaultDledgerGroup
dLegerPeers=n0-192.168.1.10:9878;n1-192.168.1.11:9878;n2-192.168.1.12:9878
dLegerSelfId=n0
listenPort=10911
节点 1:
# broker-n1.conf
enableDLegerCommitLog=true
dLegerGroup=DefaultDledgerGroup
dLegerPeers=n0-192.168.1.10:9878;n1-192.168.1.11:9878;n2-192.168.1.12:9878
dLegerSelfId=n1
listenPort=10912
节点 2:
# broker-n2.conf
enableDLegerCommitLog=true
dLegerGroup=DefaultDledgerGroup
dLegerPeers=n0-192.168.1.10:9878;n1-192.168.1.11:9878;n2-192.168.1.12:9878
dLegerSelfId=n2
listenPort=10913
四、部署实战
4.1 Docker 部署
# docker-compose.yml
version: '3'
services:
nameserver:
image: apache/rocketmq:5.0.0
command: sh mqnamesrv
ports:
- "9876:9876"
dledger-node0:
image: apache/rocketmq:5.0.0
command: sh mqbroker -n nameserver:9876 -c /opt/rocketmq/conf/broker-n0.conf
ports:
- "10911:10911"
- "9878:9878"
volumes:
- ./broker-n0.conf:/opt/rocketmq/conf/broker-n0.conf
- dledger-n0-data:/data/rocketmq/store
dledger-node1:
image: apache/rocketmq:5.0.0
command: sh mqbroker -n nameserver:9876 -c /opt/rocketmq/conf/broker-n1.conf
ports:
- "10912:10912"
- "9879:9878"
volumes:
- ./broker-n1.conf:/opt/rocketmq/conf/broker-n1.conf
- dledger-n1-data:/data/rocketmq/store
dledger-node2:
image: apache/rocketmq:5.0.0
command: sh mqbroker -n nameserver:9876 -c /opt/rocketmq/conf/broker-n2.conf
ports:
- "10913:10913"
- "9880:9878"
volumes:
- ./broker-n2.conf:/opt/rocketmq/conf/broker-n2.conf
- dledger-n2-data:/data/rocketmq/store
volumes:
dledger-n0-data:
dledger-n1-data:
dledger-n2-data:
4.2 Kubernetes 部署
# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: rocketmq-dledger
spec:
serviceName: rocketmq-dledger
replicas: 3
selector:
matchLabels:
app: rocketmq-dledger
template:
metadata:
labels:
app: rocketmq-dledger
spec:
containers:
- name: broker
image: apache/rocketmq:5.0.0
command: ["sh", "-c", "mqbroker -n rocketmq-nameserver:9876 -c /opt/rocketmq/conf/broker.conf"]
ports:
- containerPort: 10911
- containerPort: 9878
env:
- name: DLedgerSelfId
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: config
mountPath: /opt/rocketmq/conf
- name: data
mountPath: /data/rocketmq/store
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
五、故障切换
5.1 切换流程
graph TB
A[Leader 宕机] --> B[Follower 检测]
B --> C{超时?}
C -->|是 | D[发起选举]
C -->|否 | E[等待]
D --> F[投票]
F --> G{获得多数票?}
G -->|是 | H[成为新 Leader]
G -->|否 | I[选举失败]
H --> J[恢复正常服务]
5.2 切换时间
切换时间分析:
- 故障检测:3-5 秒
- 选举过程:1-3 秒
- 总切换时间:5-10 秒
5.3 切换验证
#!/bin/bash
# DLedger 切换验证脚本
echo "=== DLedger 切换验证 ==="
# 1. 查看当前 Leader
echo -e "\n当前 Leader:"
mqadmin clusterList -n ns1:9876 | grep -i leader
# 2. 停止 Leader
echo -e "\n停止 Leader..."
ssh leader-node "systemctl stop rocketmq-broker"
# 3. 等待切换
echo -e "\n等待切换..."
sleep 10
# 4. 查看新 Leader
echo -e "\n新 Leader:"
mqadmin clusterList -n ns1:9876 | grep -i leader
# 5. 验证数据一致性
echo -e "\n验证数据一致性:"
echo "test" | mqadmin sendMessage -n ns1:9876 -t test-topic
mqadmin consumeMessage -n ns1:9876 -g test-consumer -t test-topic
echo -e "\n=== 验证完成 ==="
六、数据一致性
6.1 一致性保证
DLedger 一致性保证:
1. 多数派写入
2. 日志复制
3. Leader 线性化
6.2 写入流程
sequenceDiagram
participant C as Client
participant L as Leader
participant F1 as Follower 1
participant F2 as Follower 2
C->>L: 写入请求
L->>L: 追加日志
L->>F1: 复制日志
L->>F2: 复制日志
F1-->>L: ACK
F2-->>L: ACK
L->>L: 提交(多数派确认)
L-->>C: 返回成功
6.3 读取流程
sequenceDiagram
participant C as Client
participant L as Leader
C->>L: 读取请求
L->>L: 检查日志
L-->>C: 返回数据
七、监控运维
7.1 监控指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
dledger_leader | 当前 Leader | - |
dledger_term | Raft Term | - |
dledger_commit_log_size | 提交日志大小 | - |
dledger_replication_lag | 复制延迟 | > 1000ms |
7.2 运维命令
# 查看 DLedger 状态
mqadmin clusterList -n ns1:9876
# 查看 Raft 状态
# 需要访问 DLedger 接口
curl http://localhost:9878/raft/status
# 手动触发选举
# 停止当前 Leader,Follower 会自动选举
7.3 日志分析
#!/bin/bash
# DLedger 日志分析脚本
LOG_FILE="/var/log/rocketmq/dledger.log"
echo "=== Leader 变更统计 ==="
grep "changeLeader" $LOG_FILE | \
awk '{print $1, $2, $3}' | \
sort | uniq -c | sort -rn
echo -e "\n=== 选举统计 ==="
grep "election" $LOG_FILE | \
awk '{print $1, $2, $3}' | \
sort | uniq -c | sort -rn
echo -e "\n=== 最近 Leader 变更 ==="
grep "changeLeader" $LOG_FILE | tail -10
八、最佳实践
8.1 配置建议
DLedger 配置建议:
1. 节点数量:3 或 5(奇数)
2. 跨可用区部署
3. 独立磁盘
4. 监控 Raft 状态
5. 定期演练切换
8.2 性能优化
性能优化:
1. 使用 SSD 磁盘
2. 配置合理的批次大小
3. 优化网络配置
4. 监控复制延迟
5. 建立监控告警
8.3 检查清单
运维检查:
- [ ] DLedger 状态正常
- [ ] Leader 稳定
- [ ] 复制延迟正常
- [ ] 磁盘使用率正常
- [ ] 监控告警正常
- [ ] 定期切换演练
总结
RocketMQ DLedger 的核心要点:
- 架构演进:主从模式 → DLedger 模式
- Raft 协议:Leader 选举、日志复制
- 配置方法:Broker 配置、多节点配置
- 部署实战:Docker、Kubernetes
- 故障切换:自动切换、切换验证
- 数据一致性:多数派写入、日志复制
核心要点:
- 理解 DLedger 架构优势
- 掌握 Raft 协议原理
- 配置合理的节点数量
- 建立完善的监控体系
- 定期故障切换演练
参考资料
- RocketMQ DLedger 官方文档
- DLedger GitHub
- 《RocketMQ 技术内幕》第 11 章