什么是 Raft 协议?

文章目录


我们开始深入解析分布式系统中至关重要的一致性协议—— Raft 协议(Replicated and Fault-Tolerant)

这是一套被广泛应用于一致性集群的算法(如:Etcd、Consul、TiKV、RocksDB、Zookeeper 替代品),具备易于理解、易于实现、高一致性保证等特点。


第一部分:Raft 协议概述


什么是 Raft?

Raft 是一种为了解决分布式一致性问题而设计的共识算法,属于 Paxos 协议的工程实现替代方案。

目标:在 多个节点之间复制日志,确保状态机数据一致性,容忍部分节点宕机

应用场景:

  • 主从同步数据库(如 Etcd、TiKV)
  • 配置中心(如 Consul、Nacos 选主)
  • 分布式锁、高可用服务选主

核心特性:

特性说明
高可用少数节点失效也可继续服务(多数派存活)
强一致性所有节点状态完全一致,不允许脑裂
选主机制所有写请求通过 Leader 完成

第二部分:Raft 的三大组成模块

Raft 的核心可拆解为 三个重要子机制,便于理解:

Raft = 选主机制(Leader Election)
     + 日志复制(Log Replication)
     + 安全提交(Log Commitment)

我们逐个来分析:


1. Leader Election(选主机制)

Raft 集群在任一时刻只能有一个 Leader,所有写请求只能通过 Leader 处理。

节点角色:
  • Leader:唯一写入者,负责日志复制
  • Follower:响应 Leader 的指令
  • Candidate:发起选举的节点

选举流程(定时器驱动):
  1. Follower 若长时间未收到 Leader 心跳 → 转为 Candidate;
  2. Candidate 向其他节点发送 RequestVote 请求;
  3. 若获得多数节点投票 → 成为 Leader;
  4. Leader 开始发送心跳包(AppendEntries)稳定地位。

防止冲突机制:
  • 每个节点维护 term 任期号;
  • 投票记录:每个节点每 term 只投一次票;
  • 如果有两个 Candidate 同时选举,可能出现分裂,最终都会超时重新发起选举;
  • 随机化选举超时时间避免多个节点同时成为 Candidate。

示意图(简化):

时间线 →
+---------+---------------------+-----------------+
| Follower|   Candidate         |     Leader      |
|   T1    |  请求投票           |  发送心跳        |
+---------+---------------------+-----------------+

到此为止,我们完成了 Raft 的第一个核心部分【选主机制 Leader Election】的分析。

接下来进入 Raft 协议的第二核心机制——日志复制机制(Log Replication),并继续结合现实类比 + 源码行为模拟 + 架构角度解释,让你不仅知道“它做了什么”,更知道“为什么这样做”。


第二部分:日志复制机制(Log Replication)


一、场景类比:Leader 是抄笔记的人,Follower 跟着一起抄

类比设定:
  • 班长(Leader)负责记课堂笔记;
  • 每个同学(Follower)需要保持和班长完全一致的笔记内容;
  • 每次班长记下一句话(一次日志),就要发给所有人;
  • 只有当大多数人抄完这一句,班长才把它“盖章”视为正式记入笔记本。

二、Raft 中日志的概念:

  • 所有客户端请求(写操作)会被封装成一个“日志项”(Log Entry);
  • Leader 接收后将该 Log Entry:
    1. 追加到自己的日志数组末尾
    2. 并并发地复制给所有 Follower(AppendEntries RPC)
  • Leader 会等待大多数节点成功“复制”这条日志,才认为这条日志是“已提交(committed)”。

三、核心字段(LogEntry)结构

class LogEntry {
    int term;          // 哪一任期添加的日志
    int index;         // 全局索引编号
    String command;    // 客户端指令
}

日志本质上就是一串有序的命令序列,最终将送入“状态机”执行。


四、日志复制流程图(简化):

客户端 --> Leader --> 日志追加 --> 向各Follower广播 AppendEntries

Follower  --> 校验前一条日志匹配
           --> 复制成功 → 返回ACK

Leader收集半数以上ACK → commitIndex 更新 → 应用日志

五、关键机制详解:


✅ 1. 前一条日志校验机制(PrevLogIndex + PrevLogTerm)
  • 防止日志冲突(如旧 Leader 写的日志在新 Leader 任期内失效);

  • Leader 发日志时会附带前一条日志的索引和任期:

    “我现在要发第10条,这条的前一条是:index=9,term=3,你那里也有这条吗?”

  • Follower 检查是否一致,不一致 → 回退并删除冲突部分,直到对齐。


✅ 2. 日志复制成功判定(大多数)
  • 一条日志被**多数节点成功追加(复制)**才会视为成功;
  • Leader 更新 commitIndex,然后通过 Apply() 应用到状态机(业务执行);
  • 避免了 Leader 自己写完就认定“成功”导致数据不一致。

✅ 3. Follower 是被动复制日志
  • Follower 不会主动写日志
  • 只能等待 Leader 发来的 AppendEntries;
  • 遇到缺失/冲突日志 → 按 Leader 修正,保持一致。

六、现实类比强化理解

Raft 行为现实类比
AppendEntries班长发新笔记句子
term 不一致同学之前写错了内容,需要撕掉重写
commitIndex班长打勾“这句大家都写完了”
apply正式将笔记记入成绩系统

七、设计创意与合理性来源


1. 为什么不让每个人自己写日志?

  • 分布式中,每个人都自己写,可能写法不同、顺序不同 → 状态不一致;
  • 强制“Leader 写,Follower 抄” → 保证顺序和内容一致,状态机安全。

2. 为什么必须多数写入后才 commit?

  • 多数节点拥有最新日志,即使 Leader 挂了,新 Leader 也能完整还原状态
  • 少数节点落后也没关系,但不能“少数确认” → 否则可能丢数据。

3. 为什么 Leader 不直接 apply 日志?

  • 如果 Leader 自己 apply,Follower 还没接到 → 出现不一致;
  • 所以 Raft 明确:日志写入 ≠ 提交;必须 commitIndex >= n 才能 apply。

总结这一部分重点:

说明
Log 复制逻辑Leader 发 AppendEntries 携带日志项 + 上一日志
一致性保障复制给多数后才能提交(强一致)
冲突处理Follower 与 Leader 日志冲突时回退修正
安全设计日志未 commit 不允许 apply(状态机安全)

第三部分:日志提交机制(Log Commit & Apply)


一、什么叫日志提交(Commit)?

在 Raft 中,一条日志即使已经写入所有节点的磁盘,也不能立即认为“完成”,只有满足特定条件的日志,才能称为“已提交(committed)”。


二、Commit 的意义?

  • Committed = 可被状态机执行的日志
  • 未提交的日志不能触发业务逻辑、改变状态;
  • 是 Raft 中**“日志复制 → 日志提交 → 状态执行”**这条流水线的中间关卡。

三、Raft 的提交规则(核心点)

Leader 提交日志的条件是:

某条日志,已经在“当前任期(currentTerm)”内,并且被“多数节点确认追加”**,才能 commit。


为什么要限制“当前任期”?

这是 Raft 的“安全限制设计”,防止新旧 Leader 写的日志相互覆盖。

场景举例:
  • 老 Leader 在 term 2 写了日志 A;
  • 还没来得及同步到大多数节点时宕机了;
  • term 3 出现新 Leader,写了日志 B;
  • 如果 term 2 的 A 自动提交 → 数据冲突风险!

所以 Raft 明确:只能提交当前任期成功复制的日志项!


四、commitIndex 和 lastApplied 指针(两个关键指针)

指针作用
commitIndexLeader 当前已提交日志的最大 index
lastApplied每个节点(包括 Leader)已执行日志到状态机的最大 index

日志提交流程如下:
日志复制成功 → Leader 更新 commitIndex → 通知所有 Follower 
 → 各自将 lastApplied 推进 → 执行 apply 到状态机

五、状态机执行 apply 的作用?

状态机是每个节点的“业务引擎”,执行日志对应的命令,例如:

  • 创建订单
  • 更新库存
  • 写入配置变更

只有 apply 之后,业务才真正“发生”。


为什么需要 lastApplied?

  • 防止节点“误执行”未被提交的日志;
  • 落后的节点启动后可“对比”commitIndex 与 lastApplied → 进行 apply 补偿。

六、现实生活类比理解:

Raft 元素班级类比
Log 复制班长把新笔记分发给所有人
Commit 条件超过一半同学抄完了,而且是班长任期内的笔记
Apply 到状态机所有人将这句笔记写进作业本中,老师收作业检查
lastApplied每个人写到第几题了?

七、设计的合理性(为什么这么设计才最安全?)


✅ 强一致性的保障策略:

场景Raft 的保护措施
日志未同步完就提交 → 风险限制多数派复制 + 任期校验
老 Leader 写日志 → 新 Leader 接管日志冲突回退,防止乱序
状态不一致风险commitIndex 严格控制 apply 进度

✅ 保证“新 Leader 日志一定是最完整的”:

  • 只有大多数节点拥有这条日志,新 Leader 才能再次选上;
  • 所以 Raft 提交日志,实质上也在为下一次选举做准备

八、总结三步流水线:Raft 日志处理完整流程

客户端请求
   ↓
Leader 将命令转为 LogEntry
   ↓
日志追加到本地日志数组
   ↓
AppendEntries 发往各 Follower
   ↓
大多数响应 OK → commitIndex++
   ↓
所有节点更新 lastApplied → 状态机 apply 执行

Raft 的一致性核心就在这里:

  • 所有节点 日志内容完全一致(通过复制)
  • 所有节点 日志执行顺序完全一致(通过 commit + apply)

这就是强一致性 replicated state machine 的本质。


🙋‍♂️ 欢迎留言讨论,分享你的技术经验与问题!

如果你在阅读过程中有任何问题,或者想了解更多技术细节,请在评论区留言,我会尽快回复。

📌 想要了解更多技术内容?关注我!

🎯 关注“将臣三代”,获取更多价值, 回复【面试】获取专属PDF资料下载链接!!

每周更新最新技术文章和免费资源!

🌟 独家资源:

  • 经典Java面试题解析
  • 技术架构深度拆解
  • 系统优化技巧与项目经验分享
  • AI 技术探索
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

将臣三代

每一份打赏都是创作动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值