RocketMQ DLedger 高可用集群搭建与故障排查:自动选主、Docker 网络与常见踩坑
RocketMQ 早期常见高可用方案是主从复制,但传统主从模式下 Master 故障后往往需要人工介入。RocketMQ-on-DLedger 通过 Raft 复制和自动选主能力,让一组 Broker 可以在 Leader 故障后自动选出新的 Leader,从而提升可用性。
这篇文章整理 RocketMQ 4.x DLedger 集群的搭建思路、关键配置、Docker 网络踩坑、自动选主验证和常见故障排查。需要注意:RocketMQ 5.x 之后官方更强调 Controller 模式实现自动主从切换,DLedger 方案与 5.x Controller 方案需要区分理解。
如果你想了解 RocketMQ 架构和 Broker / NameServer / Topic 等基础概念,可以先看:RocketMQ 架构设计与应用最佳实践:高可用消息队列核心解析。
RocketMQ 高可用方案演进
RocketMQ 常见高可用方案可以粗略分为:
| 方案 | 特点 | 说明 |
|---|---|---|
| 主从同步 / 异步复制 | 架构简单 | Master 故障后需要处理主从切换 |
| DLedger | 基于 Raft 自动选主 | RocketMQ 4.x 常见自动容灾方案 |
| Controller 模式 | RocketMQ 5.x 自动主从切换方案 | 更符合 5.x 高可用演进方向 |
本文重点是 RocketMQ 4.x DLedger 模式。
DLedger 是什么
RocketMQ-on-DLedger Group 是一组相同 Broker Name 的 Broker 节点,通常至少 3 个节点,通过 Raft 自动选举 Leader,其余节点作为 Follower。消息数据在 Leader 和 Follower 之间复制,以保证高可用。
核心特点:
- 至少 3 节点,满足多数派。
- Leader 负责写入。
- Follower 复制日志。
- Leader 故障后自动选主。
- 同一个集群可以部署多个 DLedger Group,实现水平扩展。
为什么不建议 2 节点?因为 Raft 需要多数派。2 节点场景下,如果 Leader 故障,只剩 1 个节点无法获得过半投票,无法正常选出新 Leader。
集群架构规划
示例规划 3 台机器:
| 节点 | IP | 角色 |
|---|---|---|
| node-0 | 172.16.0.4 |
DLedger 节点 n0 |
| node-1 | 172.16.0.17 |
DLedger 节点 n1 |
| node-2 | 172.16.0.14 |
DLedger 节点 n2 |
端口建议:
| 端口 | 作用 |
|---|---|
9876 |
NameServer |
10911 |
Broker remoting 端口 |
10909 |
Broker fast remoting 端口,常见为 listenPort - 2 |
40911 |
DLedger 节点通信端口,示例值 |
生产环境要确保这些端口在节点之间互通。
关键配置说明
典型 DLedger Broker 配置:
brokerClusterName=RaftCluster
brokerName=RaftNode00
namesrvAddr=172.16.0.4:9876;172.16.0.17:9876;172.16.0.14:9876
listenPort=10911
brokerIP1=172.16.0.4
storePathRootDir=/opt/rocketmq/store/node00
storePathCommitLog=/opt/rocketmq/store/node00/commitlog
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-172.16.0.4:40911;n1-172.16.0.17:40911;n2-172.16.0.14:40911
dLegerSelfId=n0
sendMessageThreadPoolNums=4
关键配置解释:
| 配置 | 作用 | 注意事项 |
|---|---|---|
brokerClusterName |
RocketMQ 集群名 | 同一集群保持一致 |
brokerName |
Broker 组名 | 同一 DLedger Group 中保持一致 |
namesrvAddr |
NameServer 地址 | 多个用分号分隔 |
listenPort |
Broker 对外通信端口 | 客户端和 Dashboard 要能访问 |
brokerIP1 |
Broker 注册到 NameServer 的 IP | Docker 部署时非常关键 |
storePathRootDir |
存储根目录 | 必须持久化 |
storePathCommitLog |
commitlog 目录 | 建议使用高性能磁盘 |
enableDLegerCommitLog |
是否开启 DLedger | 必须为 true |
dLegerGroup |
DLedger 组名 | 同组保持一致 |
dLegerPeers |
DLedger 节点列表 | n0/n1/n2 与 IP/端口要正确 |
dLegerSelfId |
当前节点 ID | 每个节点必须唯一 |
三台机器的配置大部分一致,主要差异是:
brokerIP1storePathRootDirstorePathCommitLogdLegerSelfId
宿主机部署思路
宿主机部署通常更直接,网络问题少。大致流程:
- 下载 RocketMQ 4.x 二进制包。
- 解压到各节点。
- 修改
conf/dledger/下的配置文件。 - 启动多个 NameServer。
- 启动 3 个 DLedger Broker。
- 创建 Topic。
- 发送和消费消息验证。
- 停掉 Leader 验证自动选主。
启动 NameServer:
nohup sh bin/mqnamesrv > /opt/rocketmq/logs/namesrv.log 2>&1 &
启动 Broker:
nohup sh bin/mqbroker -c conf/dledger/broker-n0.conf > /opt/rocketmq/logs/broker.log 2>&1 &
其他节点分别使用 broker-n1.conf、broker-n2.conf。
Docker 部署踩坑
原实践中最大的坑是 Docker 默认 bridge 网络。
如果直接使用默认 bridge,Broker 可能把容器内部 IP 注册到 NameServer,例如:
172.17.0.11:10911
此时外部客户端或 Dashboard 会从 NameServer 拿到这个地址,然后连接失败:
org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <172.17.0.11:10911> failed
原截图保留如下:


为什么 bridge 网络容易出问题
RocketMQ 客户端访问 Broker 的流程大致是:
- 客户端连接 NameServer。
- 客户端查询 Topic 路由。
- NameServer 返回 Broker 地址。
- 客户端连接 Broker 发送或消费消息。
如果 Broker 注册到 NameServer 的地址是容器内部 IP,客户端在容器外部就无法访问。
解决思路:
- 使用 host 网络。
- 正确配置
brokerIP1为宿主机可访问 IP。 - 正确映射 Broker 端口和 DLedger 端口。
- 确保防火墙和安全组放行。
Docker host 网络方案
示例:
cname="rocketmq-node1"
logs="/opt/data/${cname}"
mkdir -p ${logs}
docker run -d \
--name ${cname} \
--restart=always \
--privileged=true \
--net=host \
-v /opt/rocketmq/rocketmq-4.9.1:/usr/local/rocketmq \
-v ${logs}:/opt/data \
your-jdk-image:latest
进入容器后启动 NameServer 和 Broker:
cd /usr/local/rocketmq
nohup sh bin/mqnamesrv > /opt/data/namesrv.log 2>&1 &
nohup sh bin/mqbroker -c conf/dledger/broker-n0.conf > /opt/data/broker.log 2>&1 &
host 网络的优点是简单,Broker 注册宿主机 IP 更直接。缺点是端口隔离弱,多个容器不能使用相同端口。
brokerIP1 与端口说明
Docker 部署时建议显式配置:
brokerIP1=172.16.0.4
listenPort=10911
否则 RocketMQ 可能自动选择容器内 IP 或不符合预期的网卡 IP。
需要确保以下地址对客户端可达:
brokerIP1:10911brokerIP1:10909- DLedger 节点之间的
40911 - NameServer 的
9876
RocketMQ Dashboard
Dashboard 用于查看集群、Topic、Consumer、消息等信息。启动时需要指定 NameServer:
docker run -d \
--name rocketmq-dashboard \
-p 8080:8080 \
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=172.16.0.4:9876;172.16.0.17:9876;172.16.0.14:9876" \
apache/rocketmq-dashboard:latest
生产环境同样建议固定镜像版本,不要直接使用 latest。
验证集群状态
查看集群列表:
sh bin/mqadmin clusterList -n 172.16.0.4:9876
查看 Topic 路由:
sh bin/mqadmin topicRoute -n 172.16.0.4:9876 -t TestTopic
创建 Topic:
sh bin/mqadmin updateTopic \
-n 172.16.0.4:9876 \
-c RaftCluster \
-t TestTopic
发送消息测试:
export NAMESRV_ADDR=172.16.0.4:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
消费消息测试:
export NAMESRV_ADDR=172.16.0.4:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
验证 DLedger 自动选主
验证步骤:
- 通过 Dashboard 或
mqadmin clusterList确认当前 Leader。 - 停止 Leader 所在 Broker。
- 观察剩余两个节点是否重新选主。
- 再次发送消息验证是否可用。
- 恢复原节点,观察是否以 Follower 角色加入。
注意:至少 3 节点才能在 1 个节点故障后保持多数派。如果同时故障 2 个节点,集群将无法正常选主。
常见问题排查
1. 控制台连接 172.17.x.x 失败
现象:
RemotingConnectException: connect to <172.17.x.x:10911> failed
原因:Broker 注册了 Docker bridge 内部 IP。
处理:
- 使用 host 网络。
- 显式配置
brokerIP1为宿主机 IP。 - 确认端口映射和防火墙。
2. Broker 注册不到 NameServer
检查:
namesrvAddr是否正确。- NameServer 是否启动。
- 9876 端口是否连通。
- Broker 日志中是否有注册失败。
3. DLedger 无法选主
检查:
- 是否至少 3 个节点。
dLegerGroup是否一致。dLegerSelfId是否唯一。dLegerPeers中节点和端口是否一致。- 40911 等 DLedger 通信端口是否互通。
- 各节点时间是否相差过大。
4. 发送消息失败
检查:
- Topic 是否创建。
- Topic 路由是否正常。
- Broker 是否有 Leader。
- 客户端能否访问
brokerIP1:10911。 - Broker 磁盘是否满。
- Broker JVM 内存是否不足。
5. Broker 启动后很快退出
检查:
- JVM 内存参数是否超过机器规格。
- 存储目录权限是否正确。
storePathRootDir是否可写。- 配置文件是否存在语法错误。
原实践中也通过调整 runbroker.sh 中 JVM 参数降低内存占用:

生产环境建议
- DLedger Group 至少 3 个节点。
- 不建议 2 节点部署 DLedger。
- Broker 存储目录必须持久化。
dLegerSelfId不能重复。brokerIP1必须是客户端可访问地址。- NameServer 建议多节点部署。
- 磁盘建议使用 SSD,并监控 commitlog 写入延迟。
- 监控 Broker 存活、磁盘、堆内存、消息堆积、发送失败率。
- 不要混淆 Broker 端口、NameServer 端口和 DLedger 端口。
- 重要变更先在测试环境演练,包括 Leader 故障切换。
RocketMQ 5.x Controller 模式说明
如果你使用的是 RocketMQ 5.x,需要额外关注 Controller 模式。Controller 模式是 RocketMQ 5.x 官方文档中用于自动主从切换的重要方案,与 4.x DLedger 部署方式不同。
因此选型时建议:
- 仍使用 RocketMQ 4.x:可以参考 DLedger 方案。
- 新项目或 RocketMQ 5.x:优先阅读官方 Controller 自动主从切换文档。
- 不要混用两套方案的配置项。
总结
RocketMQ DLedger 集群搭建的关键点不是“把 3 个 Broker 启动起来”,而是确保:
- DLedger 节点满足多数派。
dLegerPeers、dLegerSelfId、dLegerGroup配置正确。- Broker 注册到 NameServer 的地址对客户端可达。
- Docker 部署时避免容器内 IP 泄露给客户端。
- 存储目录持久化,端口互通,JVM 参数合理。
- 必须通过停 Leader 的方式验证自动选主。
如果遇到控制台或客户端连接 172.17.x.x 失败,优先排查 Docker 网络和 brokerIP1。