Loading

RocketMQ高可用架构与Dledger协议解析

RocketMQ高可用架构与Dledger协议解析

1. 一段话总结

本文围绕RocketMQ 集群高级特性展开,重点介绍了基于Raft 协议实现的Dledger 文件一致性协议(解决分布式数据一致性问题,含选举、日志同步两阶段,涉及 Leader/Follower/Candidate 三种节点状态)、RocketMQ 5.X 新增的Controller 机制(分离选举与日志同步,降低 IO 负担,复用原生 CommitLog)、BrokerContainer 容器式运行机制(一个进程承载多个 Broker,提升资源利用率),并提及 5.X 版本的Proxy 组件(兼容多语言客户端),整体体现了 RocketMQ 向云原生方向的演进。


2. 思维导图

image-20250918141837448

3. 详细总结

一、Dledger 文件一致性协议

Dledger 是 RocketMQ 用于解决分布式数据一致性的核心协议,基于 Raft 协议实现,主要应对主从集群之外的 “自主选主” 场景,以下为具体拆解:

1. Dledger 高可用集群下的消息一致性问题
  • 核心定义:数据写入集群某节点后,要保证任意节点可读取,即 “分布式数据一致性”。

  • 一致性算法分类

    算法类型 代表技术 适用场景
    弱一致性算法 DNS 系统、Gossip 协议 Fabric 区块链、Cassandra、Redis Cluster、Consul
    强一致性算法 Basic-Paxos、Multi-Paxos(含 Raft 系列)、ZAB RocketMQ Dledger、Nacos JRaft、Kafka Kraft、Zookeeper

    弱一致性算法允许某些时候数据的不一致,只要保证最终一致性即可。强一致性算法降低可用性,保障任何时刻所有节点数据一致。

2. Raft 协议的基本流程

动画演示raft算法的工作原理:https://thesecretlivesofdata.com/raft/

Raft 协议通过 “选举” 和 “日志同步” 两阶段解决一致性问题,核心逻辑如下:

image-20250918231431862

  • 核心概念

    • Log 日志:节点存储的操作日志,每条为 Entry(含 Command/term/idx);
    • State Machine 状态机:Entry 最终落地的载体,需保证所有节点 Entry 顺序一致(非 “不丢失”)。
  • 两阶段工作流程

    1. Election 选举阶段
      • 所有节点启动为Follower,等待 Leader 心跳;
      • 若超过150ms-300ms 随机 Election Timeout,Follower 转为Candidate,发起投票(投自己一票);
      • Candidate 收到超过集群一半节点的投票后,转为Leader,并发送心跳确认地位;
      • 其他节点接收心跳后,转为 Follower。
    2. Log Replication 日志同步阶段
      • Leader 接收客户端请求,生成 Entry 并同步到所有 Follower;
      • Follower 将 Entry 存入本地 Log(uncommited 状态);
      • 多数节点确认存储 Entry后,Leader 标记 Entry 为 commited,并通知 Follower 提交到 State Machine。
  • 三种节点状态

    节点状态 核心职责 状态切换触发条件
    Leader 1. 多数派选举产生;2. 发送心跳;3. 响应客户端请求;4. 同步操作日志 Candidate 获多数投票
    Follower 1. 参与选举投票;2. 同步 Leader 数据;3. 接收心跳 启动时默认;接收 Leader 心跳;Candidate 未获多数投票
    Candidate 发起投票,竞选 Leader Follower 超时未收 Leader 心跳
  • 防脑裂机制:引入Term 任期,每个任期以选举开始,同一任期最多 1 个 Leader;若节点发现更高 Term,立即更新自身 Term 并转为 Follower(回滚自身数据,匹配新leader的数据)。

  • CAP 取舍:优先保证CP(一致性 + 分区容错性),放弃 A(可用性),与 Eureka(保证 AP)形成对比。

发生脑裂,如:存在ABCDE四个节点,A为主节点,发生网络分区,
1.AB互通,写入主节点A的数据同步到B,发现同步的节点数未超过一半,所以一直都是uncommitted。
2.CDE无法联系到主节点A,重新选举C为主节点,且任期term+1,因为超过半数节点所以C写入的指令最终可以committed。
3.网络分区恢复后,原主节点A发现新主节点C的term比自己高,于是回滚数据,认C做老大。

3. Raft 协议的基础实现机制拆解

image-20250918233626328

  • 数据结构

    数据类型 所属节点 核心内容
    公共数据 所有节点 1. currentTerm:当前任期;2. votedFor:当前任期投票对象;3. log []:日志条目(含 Command/term/idx);4. commitIndex:已提交 Entry 的索引;5. lastApplied:已执行 Entry 的索引(lastApplied≤commitIndex)
    Leader 特有数据 Leader 节点 1. nextIndex []:每个 Follower 的同步进度;2. matchIndex []:每个 Follower 的复制进度(等待Follower 确认中)
  • 核心 RPC 请求

    RPC 类型 发起方 核心参数 响应参数
    投票请求 Candidate term(当前任期)、candidateId(候选人 ID)、lastLogIndex/lastLogTerm(候选人最后日志信息) term(当前任期)、voteGranted(是否支持)
    心跳 / 日志同步请求 Leader term(Leader 任期)、leaderId(Leader ID)、entries [](日志条目,心跳为空)、leaderCommit(Leader 已提交索引) term(当前任期)、success(是否成功)
4. RocketMQ 中的 Raft 实现

RocketMQ 基于 Dledger 框架实现 Raft,核心代码分布如下:

  • 1. 节点基础状态(MemberState 类)
    • 核心字段:selfId(节点 ID)、role(节点角色)、leaderId(当前 Leader ID)、currTerm(当前任期)、currVoteFor(当前任期投票对象)、ledgerEndIndex/ledgerEndTerm(最后一条 Entry 的索引 / 任期)。
  • 2. Leader 同步进度管理(DLedgerEntryPusher 类)
    • dispatcherMap:记录每个 Follower 的同步状态,对应 Raft 的 nextIndex [];
    • pendingMap:记录待确认的消息,对应 Raft 的 matchIndex []。
  • 3. LogEntry 设计(DLedgerEntry 类)
    • 核心字段:index(索引)、term(任期)、body(消息体,对应 RocketMQ 的 CommitLog);
    • 特殊说明:Dledger 集群的 CommitLog 为DLedgerCommitLog(子类),与主从集群的 CommitLog 不通用,无法直接迁移。
  • 4. 状态机(StateMachine 接口)
    • 核心逻辑:定义 Entry 提交操作,记录 lastAppliedIndex(封装于 StateMachineCaller)和 CommitIndex;
    • 执行流程:onCommited 方法封装提交任务,放入队列排队执行,具体逻辑由 RocketMQ 实现。
  • 5. RPC 请求(protocol 包)
    • 核心请求 / 响应类:VoteRequest/VoteResponse(投票)、PushEntryRequest/PushEntryResponse(日志同步)、HeartBeatRequest/HeartBeatResponse(心跳)等。

二、主从节点切换的高可用集群

为解决 Dledger 集群 “日志体积大、IO 负担重” 的问题,RocketMQ 5.X 新增Controller 机制,核心设计如下:

  • 核心目标:复用 Raft 选举的高可用特性,同时使用 RocketMQ 原生 CommitLog(避免 Dledger 日志膨胀)。
  • 部署方式:支持独立部署或嵌入 NameServer 部署,具体参考官网文档(https://rocketmq.apache.org/zh/docs/deploymentOperations/03autofailover)。
  • 设计思路:分离 “选举” 与 “日志同步”,选举由 Controller 负责,日志同步沿用原生主从同步逻辑,降低 IO 开销。

img

三、RocketMQ 的 BrokerContainer 容器式运行机制

针对 4.X 版本 “资源利用率低” 的痛点,5.X 推出 BrokerContainer,具体改进如下:

  • 4.X 版本痛点:一个进程对应一个 Broker,主从负载不均(Master 繁忙、Slave 仅备援),服务器资源浪费。
  • 5.X 改进核心:一个 BrokerContainer 进程可承载多个 Broker(支持 Master/Slave/DledgerBroker 混合),实现节点对等部署,提升资源利用率。
  • 部署与配置
    1. 启动脚本bin/mqbrokercontainer -c broker-container.conf(-c 指定配置文件);
    2. 核心配置参数(表格 5):
      配置参数 作用 示例值
      listenPort 接收 mqadmin 命令的端口 10811
      namesrvAddr 指定 NameServer 地址 worker1:9876;worker2:9876;worker3:9876
      fetchNamesrvAddrByAddressServer 是否自动获取 NameServer 地址 false
      brokerConfigPaths 指定添加到 Container 的多个 Broker 配置路径,用 “:” 分隔 /app/rocketmq/conf/2m-2s-async/broker-b-s.properties:/app/rocketmq/conf/2m-2s-async/broker-a.properties
  • 扩展能力:支持通过 mqadmin 工具动态添加 / 移除 Broker(无需重启 Container)。

四、RocketMQ 的集群架构总结

RocketMQ 5.X 版本(2022 年 9 月推出)向云原生方向大幅演进,核心升级包括:

  1. 高可用增强:新增 Controller 机制,优化主从切换与日志同步效率;
  2. 资源利用率提升:推出 BrokerContainer,实现单进程多 Broker 部署;
  3. 多语言兼容:新增Proxy 组件,支持多语言客户端(Java 客户端可省略),部署参考官网(https://rocketmq.apache.org/zh/docs/quickStart/01quickstart);
  4. 架构灵活性:Controller、Proxy 支持与 Broker 组合部署或独立部署,适配不同场景需求。

4. 关键问题

问题 1:RocketMQ 的 Dledger 协议如何解决分布式数据一致性问题?其核心依赖的 Raft 协议有哪些关键设计?

答案:Dledger 通过集成 Raft 协议解决分布式数据一致性问题,核心逻辑如下:

  1. 一致性问题拆解:Dledger 针对服务宕机、网络抖动、网速差异、快速响应四大挑战,采用强一致性的 Raft 协议,保证集群内日志 Entry 顺序一致;
  2. Raft 协议关键设计
    • 两阶段机制:通过 “Election 选举”(多数派产生 Leader,避免脑裂)和 “Log Replication 日志同步”(多数节点确认后提交 Entry,保证一致性)实现核心流程;
    • Term 任期:每个任期仅允许 1 个 Leader,节点发现更高 Term 时自动降级,防止脑裂;
    • 节点状态分工:Leader 响应请求 + 同步日志、Follower 投票 + 同步数据、Candidate 竞选 Leader,明确角色职责;
    • 多数派确认:选举和日志提交均需 “超过集群一半节点” 确认,保证分区容错性。

问题 2:RocketMQ 5.X 版本为何引入 Controller 机制和 BrokerContainer?两者分别解决了此前版本的哪些痛点?

答案:两者均为解决 4.X 及 Dledger 集群的核心痛点而设计,具体如下:

  1. Controller 机制
    • 解决痛点:Dledger 集群将 “选举” 与 “日志同步” 绑定,导致日志体积膨胀(非原生 CommitLog),增加写 IO 负担;
    • 设计目标:分离 Raft 选举(保证高可用)与日志同步(复用 RocketMQ 原生 CommitLog),降低 IO 开销,同时保留自主选主能力。
  2. BrokerContainer
    • 解决痛点:4.X 版本 “一个进程对应一个 Broker”,主从负载不均(Master 繁忙、Slave 仅备援),服务器 CPU、内存等资源利用率低;
    • 设计目标:一个进程承载多个 Broker(支持 Master/Slave/DledgerBroker 混合),通过对等部署提升资源利用率,且支持动态添加 / 移除 Broker。

问题 3:RocketMQ 中 Dledger 的 LogEntry 设计有何特殊之处?为何 Dledger 集群与主从集群的 CommitLog 无法直接迁移?

答案:Dledger 的 LogEntry 设计及 CommitLog 兼容性问题如下:

  1. LogEntry 设计特殊之处
    • 核心类:io.openmessaging.storage.dledger.entry.DLedgerEntry,包含 index(Entry 索引)、term(所属任期)、body(消息体)等字段,其中 body 对应 RocketMQ 的日志数据;
    • 绑定 Raft 元数据:LogEntry 需携带 term 和 index,用于 Raft 协议的日志同步与顺序校验,这是原生 CommitLog(无 Raft 元数据)所不具备的。
  2. CommitLog 无法迁移的原因
    • Dledger 集群使用DLedgerCommitLog(CommitLog 的子类),其日志结构包含 Raft 协议必需的 term、index 等元数据;
    • 主从集群使用原生 CommitLog,无上述 Raft 元数据,两者日志格式不兼容,因此无法直接迁移。
posted @ 2025-09-18 17:37  流火无心  阅读(108)  评论(0)    收藏  举报