《深入理解 Nacos 集群与 Raft 协议》系列四:日志复制机制:Raft 如何确保提交可靠且幂等

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

大家好,我是G探险者!

在前几篇中我们介绍了选主与日志对比机制,它们保证了"谁能成为 Leader"以及"Leader 的日志是否可靠"。

而当 Leader 已选定,系统需要把客户端的写请求写入所有节点的日志中,这个过程就称为 日志复制(Log Replication)

本篇将讲解:

  • Raft 是如何进行日志复制的?
  • 如何判断日志是否成功提交?
  • 如何保障幂等与一致性?

一、基本流程:写入 Leader,然后复制给 Follower

在 Raft 中,所有写操作必须提交到 Leader 节点,流程如下:

  1. 客户端发送写请求给 Leader
  2. Leader 将写请求封装为日志条目(LogEntry)
  3. Leader 将该日志追加到本地日志中
  4. 并并发向所有 Follower 发送 AppendEntries 请求
  5. Follower 收到后尝试匹配前一条日志(前向一致性)
  6. 匹配成功后,Follower 追加日志,并回复成功
  7. Leader 收到超过半数节点确认后 → 标记日志为"已提交"
  8. Leader 通知 Follower 提交该日志(commit)
  9. Leader 应用日志到状态机并响应客户端

整个过程看似复杂,但每一步都有其必要性。


二、什么是日志"提交"成功?

Raft 中,一条日志被称为"已提交",必须满足:

该日志由 Leader 追加,且已被超过半数节点确认持久化。

这样做的意义是:

  • 即使 Leader 崩溃,仍有过半节点持有该日志
  • 下次选主,一定会选出有这条日志的节点为新 Leader(见第 3 篇)

已提交的日志,不会丢。


三、AppendEntries 的核心要素

AppendEntries 请求中包含:

  • leaderTerm:当前任期
  • prevLogIndex + prevLogTerm:前一日志索引+任期(对齐用)
  • entries:本次追加的日志条目(可能为空,仅用于心跳)
  • leaderCommit:Leader 当前提交的位置

Follower 会进行对比:

  • 若 prevLogIndex 和 prevLogTerm 不一致 → 拒绝请求
  • 否则 → 覆盖旧日志,从当前追加新日志

四、如何保证日志幂等?

在网络不稳定情况下,可能出现 AppendEntries 重发、乱序。

Raft 通过"前一条日志"对齐机制来保证幂等性:

  • 每次发送都携带 prevLogIndex/prevLogTerm
  • 若日志有误,Follower 会拒绝,Leader 自动回退并重发
  • 不会重复插入相同日志,也不会错位插入

→ 这是一种 乐观+校验补偿式的强一致写入机制


五、提交顺序与状态机执行

Raft 要求日志是顺序提交的:

  • 日志 index 是严格递增的
  • 必须 index=1 提交后才能提交 index=2

Leader 提交一条日志后:

  • 会逐步推进 commitIndex
  • Leader 会把 commitIndex 推送给所有 Follower
  • 每个 Follower 在收到时才会"真正执行"该日志到状态机

→ 所有节点最终状态机执行的日志是一致的、顺序的


六、断电/重启后如何恢复日志?

因为日志会持久化在本地磁盘上,所以:

  • Raft 节点宕机重启时,会从本地恢复日志
  • 并向新 Leader 进行日志对齐补偿

Raft 的一致性依赖于 持久化日志+对比同步机制,而非内存


七、日志复制在 Nacos 中的体现

你可以看到类似日志:

text 复制代码
[RAFT] AppendEntries from leader, prevIndex=5, term=7
[RAFT] Log mismatch, conflict at index=5, localTerm=6
[RAFT] Truncate logs from index=5
[RAFT] Append new log entries...
[RAFT] Advance commitIndex to 8

这些就是日志对齐 + 复制 + 提交的全过程。


总结

Raft 的日志复制机制,是系统强一致性的核心支柱:

  • 所有写请求必须经 Leader 统一调度
  • 复制必须超过半数成功才算提交
  • 提交后才能执行,确保所有节点状态一致
  • Follower 校验 + 回退机制保证了幂等性

下一篇,我们将以 Nacos 为例讲解:

💡 如果集群未过半节点存活,为什么整个系统不可用?

敬请期待第 5 篇!

相关推荐
uzong3 小时前
面试官:Redis中的 16 库同时发送命令,服务端是串行执行还是并行执行
后端·面试·架构
追逐时光者4 小时前
.NET 使用 MethodTimer 进行运行耗时统计提升代码的整洁性与可维护性!
后端·.net
你的人类朋友5 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
David爱编程6 小时前
面试必问!线程生命周期与状态转换详解
java·后端
LKAI.7 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi
Victor3567 小时前
Redis(11)如何通过命令行操作Redis?
后端
Victor3567 小时前
Redis(10)如何连接到Redis服务器?
后端
他日若遂凌云志9 小时前
深入剖析 Fantasy 框架的消息设计与序列化机制:协同架构下的高效转换与场景适配
后端
快手技术9 小时前
快手Klear-Reasoner登顶8B模型榜首,GPPO算法双效强化稳定性与探索能力!
后端
二闹9 小时前
三个注解,到底该用哪一个?别再傻傻分不清了!
后端