RocketMQ DLedger:Raft 协议实现 源码详解

RocketMQ DLedger:Raft协议源码详解

🚀 RocketMQ DLedger:Raft 协议实现 源码详解

RocketMQ 在 4.5+ 版本引入了 DLedger(Distributed Ledger) 模块,基于 Raft 一致性协议 实现了自动选主、强一致性、高可用的存储架构,解决了传统主从模式缺乏自动故障转移的问题。

本文将深入 DLedger 源码dledger 模块),解析其如何实现 Raft 协议的核心机制:Leader 选举、日志复制、安全性保证


一、DLedger 架构概览

+-------------+       +-------------+       +-------------+
|   Node-1     |<----->|   Node-2     |<----->|   Node-3     |
|  (Follower)  |       |   (Leader)   |       |  (Follower)  |
+-------------+       +-------------+       +-------------+
       ↑                     ↑                     ↑
       |                   Heartbeat               |
       +-------- Replicate Log Entries ----------->+
  • DLedger Group:由 3 或 5 个节点组成,基于 Raft 协议运行
  • Leader:唯一可写节点,处理所有写请求
  • Follower:只读,从 Leader 同步数据
  • 自动选主:Leader 宕机后自动选举新 Leader

✅ DLedger 是 RocketMQ 实现 真·高可用 的核心组件。


二、源码环境准备

  • 源码地址:https://github.com/openmessaging/openmessaging-storage-dledger
  • 分支master(独立项目,被 RocketMQ 引用)
  • 核心模块
    • dledger:核心 Raft 实现
    • entry:日志条目
    • quorum:多数派确认
    • statemachine:状态机

三、Raft 协议核心机制回顾

机制说明
Leader 选举节点通过投票选出 Leader
日志复制Leader 将日志复制给 Follower,多数派确认后提交
安全性保证已提交日志不会被覆盖
任期(Term)每次选举生成新 Term,防止脑裂

四、1. Leader 选举(Leader Election)

📌 触发时机:

  • 初始启动
  • Leader 心跳超时
  • 节点网络分区恢复

🔧 入口:DLedgerLeaderElector#handleHeartbeat

// DLedgerLeaderElector.java
public void handleHeartbeat(DLedgerHeartBeatRequest request) {
    if (request.getTerm() > dLedgerLeaderElector.getTerm()) {
        // 收到更高 Term → 转为 Follower
        changeToCandidate(request.getTerm());
    }
}

🔧 选举流程:ElectingState#elect

// ElectingState.java
public void elect() {
    // 1. 自增 Term
    long term = dLedgerLeaderElector.getTerm() + 1;
    dLedgerLeaderElector.setTerm(term);

    // 2. 投票给自己
    votesMap.put(dLedgerServer.getMemberId(), new VoteResultEntry(true, System.currentTimeMillis()));

    // 3. 向其他节点发送投票请求
    for (String peer : peers) {
        sendVoteRequest(peer, term);
    }

    // 4. 等待投票结果
    waitForVotes();
}

🔧 投票请求:VoteRequest

// VoteRequest.java
public class VoteRequest extends DLedgerRequest {
    private long term;
    private String candidateId;
    private long lastLogIndex;
    private long lastLogTerm;
}
投票规则(安全性):
  1. 同一 Term 只能投一次票
  2. 只能投给日志更完整(lastLogIndex 更大)的节点
  3. 收到更高 Term 的请求 → 转为 Follower

🔧 投票响应:VoteResponse

// VoteResponse.java
public class VoteResponse extends DLedgerResponse {
    private boolean voteGranted; // 是否同意
    private long term;           // 当前 Term
}

🔧 选举成功条件:

// QuorumUtil.java
public boolean isQuorum(int grantedVotes) {
    return grantedVotes > peers.size() / 2; // 多数派同意
}

✅ 3 节点允许 1 个故障,5 节点允许 2 个。


五、2. 日志复制(Log Replication)

📌 流程:

  1. 客户端写入 Leader
  2. Leader 写入本地日志
  3. 并行发送 AppendEntries 给 Follower
  4. 多数派确认后,提交日志
  5. 返回客户端

🔧 入口:DLedgerServer#handleAppend

// DLedgerServer.java
public CompletableFuture<AppendEntryResponse> handleAppend(AppendEntryRequest request) {
    if (role != Role.LEADER) {
        // 非 Leader → 转发给 Leader
        return forwardToLeader(request);
    }

    // 写入本地日志
    DLedgerEntry entry = new DLedgerEntry();
    entry.setData(request.getBody());
    entry.setIndex(dLedgerStore.getLedgerEndIndex() + 1);
    entry.setTerm(request.getTerm());

    dLedgerStore.append(entry);

    // 并行复制给 Follower
    return replicateToFollowers(entry);
}

🔧 复制逻辑:DLedgerReplicator#replicate

// DLedgerReplicator.java
private CompletableFuture<AppendEntryResponse> replicate(DLedgerEntry entry) {
    // 1. 并行发送 AppendEntries 给所有 Follower
    List<CompletableFuture<AppendEntryResponse>> futures = new ArrayList<>();
    for (String peer : peers) {
        futures.add(sendAppendEntries(peer, entry));
    }

    // 2. 等待多数派确认
    return QuorumFuture.wrap(futures, peers.size() / 2 + 1);
}

🔧 追加请求:AppendEntryRequest

// AppendEntryRequest.java
public class AppendEntryRequest extends DLedgerRequest {
    private long term;
    private String leaderId;
    private long prevLogIndex;
    private long prevLogTerm;
    private List<ByteBuf> entries; // 日志条目
    private long leaderCommit;
}
日志一致性检查:
  • prevLogIndexprevLogTerm 必须匹配,否则拒绝
  • 保证日志连续性

🔧 提交日志:DLedgerCommitLog#commit

// DLedgerCommitLog.java
public void commit(long commitIndex) {
    while (lastCommittedIndex < commitIndex) {
        DLedgerEntry entry = dLedgerStore.get(++lastCommittedIndex);
        // 通知状态机(如 RocketMQ 的 CommitLog)
        stateMachine.onCommitted(entry);
    }
}

✅ 提交后,消息才可被消费。


六、3. 安全性与状态机

📌 安全性保证:

  • 选举限制:只投票给日志更完整的节点
  • 日志匹配:保证 Leader 和 Follower 日志一致
  • Leader 完整性:Leader 拥有所有已提交日志

🔧 状态机:StateMachine

// StateMachine.java
public interface StateMachine {
    void onApply(DLedgerEntry entry);     // 应用日志
    void onCommitted(DLedgerEntry entry); // 提交日志
    void onSnapshotSave();                // 保存快照
    void onSnapshotLoad();                // 加载快照
}
RocketMQ 集成:
  • DLedgerCommitLog 作为状态机,将日志写入 RocketMQ 的 CommitLog
  • 实现“日志复制 + 消息存储”的无缝衔接

七、DLedger 与 RocketMQ 集成

📌 RocketMQ 使用 DLedger 作为存储引擎:

# broker.conf
enableDLegerCommitLog=true
dLegerGroup=raft_group_01
dLegerPeers=n0-192.168.0.10:40911;n1-192.168.0.11:40911;n2-192.168.0.12:40911
dLegerSelfId=n0

🔧 启动流程:

  1. BrokerController 检测到 enableDLegerCommitLog=true
  2. 创建 DLedgerCommitLog 替代传统 CommitLog
  3. 启动 DLedgerServer,加入 Raft Group
  4. 自动选举 Leader,开始服务

八、总结:DLedger 核心机制源码链路

1. Leader 选举

心跳超时 → 转为 Candidate
   ↓
自增 Term → 投票给自己
   ↓
发送 VoteRequest → 收集投票
   ↓
多数派同意 → 成为 Leader

2. 日志复制

客户端写入 Leader
   ↓
Leader 写本地日志
   ↓
并行发送 AppendEntries
   ↓
多数派确认 → 提交日志
   ↓
返回客户端

3. 安全性

投票限制:只投给日志更完整的节点
日志匹配:prevLogIndex/prevLogTerm 必须一致
Leader 完整性:Leader 拥有所有已提交日志

✅ 总结

机制核心类说明
Leader 选举DLedgerLeaderElector基于 Term 和投票
日志复制DLedgerReplicator并行复制 + 多数派确认
状态机StateMachine与 RocketMQ CommitLog 集成
网络通信DLedgerRpcNettyServiceNetty 实现 RPC

🚀 一句话总结:
RocketMQ DLedger 通过 Raft 协议 实现了 “自动选主 + 强一致性 + 高可用”
彻底解决了传统主从模式的单点故障问题,
是 RocketMQ 迈向云原生、高可用架构的关键一步。

掌握 DLedger 源码,你就能理解 RocketMQ 如何在分布式环境下保证数据一致性和服务连续性,为构建可靠消息系统打下坚实基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值