《深入理解 Nacos 集群与 Raft 协议》系列三:日志对比机制:Raft 如何防止数据丢失与错误选主

《深入理解 Nacos 集群与 Raft 协议》系列

大家好,我是G探险者!

在第 2 篇中,我们讲解了 Raft 的选主过程。但单靠"投票数过半"并不能完全保障新 Leader 的安全性。

为了防止数据丢失和不合法的 Leader 被选出,Raft 引入了关键的 日志对比机制(Log Comparison)。这一机制确保:

只有拥有"最新日志"的节点才能当选 Leader。

那么,"最新"是如何判断的?这个机制是如何工作的?又是如何保障数据一致性的?我们逐一解析。


一、为什么投票不能只看任期?

设想一个场景:

  • 第 1 次提交时,A 是 Leader,ABC 同步成功
  • A 崩溃后,CDE 成为候选人集群
  • D 发起选主,但 D 的日志落后于之前提交的日志

如果这时 D 被选为 Leader,就会出现:

  • D 发起的 AppendEntries 会让 C 删除与其不同的日志项
  • 导致之前提交的日志被回滚,数据丢失!

这就是 "旧节点错误地成为 Leader" 导致的严重后果。

Raft 设计了日志对比机制来彻底避免这种情况。


二、日志对比的两个关键字段

当 Candidate 发起选举时,会在 RequestVote 请求中附带:

text 复制代码
lastLogIndex:最后一条日志的索引
lastLogTerm:最后一条日志的任期号

Follower 收到投票请求时,会进行判断:

候选人的日志是否"更新"?

判断规则如下:

  1. 谁的 lastLogTerm 大,谁的日志更新
  2. 如果 lastLogTerm 相同,则看 lastLogIndex 谁大

只有候选人日志"更新"时,Follower 才会投票。


三、为什么这样判断就足够安全?

这种机制保证了:

  • 所有当选的 Leader,日志一定不比大多数节点旧
  • 从而不会覆盖大多数节点上已经存在的日志

换句话说,新 Leader 必须包含"前任 Leader 已提交的日志"

这就实现了我们在第 1 篇中提到的:"每次提交的多数派之间必须有交集",从而实现日志递进一致性。


四、举个例子来理解日志对比

假设 5 个节点:A、B、C、D、E

  • A 是 Leader,提交了 index=3 的日志
  • 复制到了 ABC 节点

这时 A、B 宕机,C、D、E 存活。

  • D 发起选举,日志只到 index=1(旧)
  • C 拒绝投票,因为自己的 lastLogTerm/index 更新

→ D 选举失败,不能成为 Leader

接下来 C 发起选举,D、E 都投票 → 成功成为新 Leader

因为 C 拥有最完整的日志,才有资格成为 Leader。


五、Raft 如何保证最终一致性?

有了日志对比机制,Raft 能做到:

  • 选主只选"最新"的节点,防止数据倒退
  • 新 Leader 会用自己的日志覆盖旧节点的非一致日志
  • AppendEntries 中包含前一个日志的索引和任期,作为对齐基准

最终,每个节点的日志都会逐步和 Leader 保持一致。


六、在 Nacos 中的体现

你可以从以下场景中感受到日志对比的存在:

  • 节点日志落后,迟迟不能当选 Leader
  • 选主期间频繁看到日志校验失败的投票日志
  • 某节点刚启动,必须通过日志对齐后才成为稳定成员

这些机制背后,都是为了实现一致性的日志对比与对齐。


七、总结

Raft 的日志对比机制,是保障"选主安全性"和"日志最终一致性"的核心:

  • 投票时检查候选人日志是否比自己新
  • 防止日志回滚,避免脑裂与数据丢失
  • 所有新 Leader 都必须有前任 Leader 的提交副本

下一篇我们将继续讲解:

💡 Raft 日志是如何复制的?提交策略、确认机制与幂等性保障

敬请期待第 4 篇!

相关推荐
2302_8097983233 分钟前
【JavaWeb】Docker项目部署
java·运维·后端·青少年编程·docker·容器
zhojiew1 小时前
关于akka官方quickstart示例程序(scala)的记录
后端·scala
sclibingqing1 小时前
SpringBoot项目接口集中测试方法及实现
java·spring boot·后端
Theodore_10221 小时前
大数据(2) 大数据处理架构Hadoop
大数据·服务器·hadoop·分布式·ubuntu·架构
JohnYan2 小时前
Bun技术评估 - 03 HTTP Server
javascript·后端·bun
周末程序猿2 小时前
Linux高性能网络编程十谈|C++11实现22种高并发模型
后端·面试
ZHOU_WUYI3 小时前
Flask与Celery 项目应用(shared_task使用)
后端·python·flask
冒泡的肥皂3 小时前
强大的ANTLR4语法解析器入门demo
后端·搜索引擎·编程语言
IT_陈寒4 小时前
Element Plus 2.10.0 重磅发布!新增Splitter组件
前端·人工智能·后端
有梦想的攻城狮4 小时前
spring中的@RabbitListener注解详解
java·后端·spring·rabbitlistener