当前位置: 首页 > ai >正文

《深入理解 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 请求中附带:

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 篇!

http://www.xdnf.cn/news/12851.html

相关文章:

  • 讲述我的plc自学之路 第十三章
  • 遍历 Map 类型集合的方法汇总
  • 第1篇:BLE 是什么?与经典蓝牙有何区别?
  • 【第三十九周】ViLT
  • 《高等数学》(同济大学·第7版)第三章第二节“洛必达法则“详解
  • C语言编程习题Day1
  • 曼昆《经济学原理》第九版 第七章消费者、生产者与市场效率
  • 解决Vscode JDK插件源码缺失问题
  • 手搓transformer
  • 【数据结构与算法】从广度优先搜索到Dijkstra算法解决单源最短路问题
  • springboot3.5整合Spring Security6.5默认密码没有打印输出控制台排查过程
  • DeepSeek 终章:破局之路,未来已来
  • 图像超分辨率
  • 爱抚宠物小程序源代码+lw+ppt
  • 数据库学习(三)——MySQL锁
  • for循环应用
  • 【西门子杯工业嵌入式-6-ADC采样基础】
  • 详细叙述一下Spring如何创建bean
  • Python训练营打卡DAY48
  • 华为IP(8)(OSPF开放最短路径优先)
  • 树状数组学习笔记
  • 振动力学:无阻尼多自由度系统(受迫振动)
  • SQL进阶之旅 Day 21:临时表与内存表应用
  • Spring MVC请求处理流程和DispatcherServlet机制解析
  • 【Go语言基础【18】】Map基础
  • 2025-04-28-堆、栈及其应用分析
  • 算法专题七:分治
  • 【CATIA的二次开发23】抽象对象Document涉及文档激活控制的方法
  • serv00 ssh登录保活脚本-邮件通知版
  • 【构建】CMake 常用函数和命令清单