ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Raft 详解:从 Leader 选举到日志复制,彻底理解分布式一致性

Raft 详解:从 Leader 选举到日志复制,彻底理解分布式一致性 文章目录Raft 详解从 Leader 选举到日志复制彻底理解分布式一致性一、Raft 到底解决什么问题二、Raft 集群中的三种角色三、Leader 是干什么的四、Leader 挂了怎么办五、Master2 能收到 Leader 心跳Master3 收不到怎么办六、那 Master3 会不会自己发起选举Master2 仍然能够收到 Master1 的心跳七、这就是 Raft 对网络分区的处理八、为什么 Raft 要求“多数派”九、网络分区是 Raft 非常重要的场景十、旧 Leader 恢复之后怎么办十一、Term 到底是什么十二、“一个 Term 只能有一个 Leader”是什么意思十三、为什么旧 Leader 不会“复活夺权”十四、旧 Leader 上可能还有一些“旧日志”怎么办十五、所有操作都是 Leader 做吗① 写操作十六、Follower 完全不操作吗1. 接收 Leader 心跳2. 接收日志3. 保存日志4. 参与投票5. 参与提交十七、Raft 的写操作完整过程Step 1客户端请求 LeaderStep 2Leader 写入日志Step 3复制给 FollowerStep 4Follower 保存Step 5获得多数派Step 6CommitStep 7应用到状态机十八、Raft 的核心其实是“日志复制”十九、Raft 的三个核心模块1. Leader Election2. Log Replication3. Safety二十、Leader Election 是怎么发生的二十一、为什么每个节点的 Election Timeout 不一样二十二、Raft 如何防止一个旧 Leader继续写数据二十三、Raft 和 CAP 的关系二十四、3 节点 Raft 为什么通常比 2 节点好二十五、Raft 和 SeaweedFS Master 的关系二十六、把整个 Raft 过程串起来M1 挂掉M1 恢复二十七、最终用一张图理解 RaftRaft 详解从 Leader 选举到日志复制彻底理解分布式一致性Raft 是分布式系统中非常经典的一种一致性算法Consensus Algorithm。它解决的核心问题是当多个节点共同维护一份状态时如何保证这些节点看到的状态是一致的并且在部分节点故障的情况下系统仍然能够继续工作。SeaweedFS、etcd、Consul、TiKV 等分布式系统都会涉及 Raft。一、Raft 到底解决什么问题假设有三个 MasterMaster Cluster ┌──────────────┐ │ Master 1 │ │ Leader │ └──────┬───────┘ │ ┌──────┴──────┐ ↓ ↓ ┌────────────┐ ┌────────────┐ │ Master 2 │ │ Master 3 │ │ Follower │ │ Follower │ └────────────┘ └────────────┘它们需要共同维护Volume 1001 → Server A Volume 1002 → Server B Volume 1003 → Server C如果没有 Raft可能出现Master1 Volume 1001 Volume 1002 Volume 1003 Master2 Volume 1001 Volume 1002 Master3 Volume 1001 Volume 1003那么集群到底相信谁这就是分布式系统最核心的问题之一多个节点如何对同一件事情达成一致Raft 就是解决这个问题的一种方法。二、Raft 集群中的三种角色Raft 节点有三个主要角色Follower Candidate Leader状态转换大致如下超时 ┌────────────────────┐ │ ↓ ┌─────────┐ ┌───────────┐ │ Follower│ ───────→ │ Candidate │ └────▲────┘ └─────┬─────┘ │ │ │ │ 获得多数票 │ ↓ │ ┌──────────┐ └────────────── │ Leader │ 发现更高Term └──────────┘三、Leader 是干什么的Leader 是 Raft 集群中的核心角色。例如Master1 Leader Master2 Follower Master3 Follower客户端发送创建 Volume 1004通常会由 Leader 接收Client │ │ 创建 Volume 1004 ↓ Master1 Leader然后 Leader 把这个操作复制给 FollowerMaster1 Leader │ ┌─────┴─────┐ ↓ ↓ Master2 Master3 Follower Follower四、Leader 挂了怎么办这是 Raft 最重要的能力之一。假设Master1 Leader Master2 Follower Master3 FollowerMaster1 突然宕机Master1 ❌ Master2 Master3Master2 和 Master3 一段时间没有收到 Leader 的心跳。它们都会认为Leader 可能已经挂了。于是可能开始 Leader Election。五、Master2 能收到 Leader 心跳Master3 收不到怎么办这个问题非常重要。假设Master1 Leader / \ 心跳 X ↓ ↓ Master2 Master3Master2收到 Master1 心跳Master3收不到 Master1 心跳同时Master2 ←→ Master3之间网络正常。那么Master3 不会因为收不到 Leader 心跳就认为 Master2 挂了。它只会认为我收不到 Leader并不会认为Master2 挂了因为 Raft 节点之间的故障判断是针对具体节点之间的通信。六、那 Master3 会不会自己发起选举有可能。Master3 的 Election Timeout 到期Master3 我已经很久没有收到 Leader Master1 的心跳。 那么 Master1 可能挂了。于是 Master3 可能变成 CandidateMaster3 Candidate然后发起RequestVote请求Master2 你投我一票吗 Master1 已经联系不上。但是这里存在一个关键问题Master2 仍然能够收到 Master1 的心跳因此 Master2 会认为Master1 仍然是 Leader如果 Master3 发起选举Master3 → Master2 请投票给我。Master2 通常不会投票给 Master3因为它仍然认为当前 Leader 有效。所以Master2 → Master3 拒绝投票Master3 无法获得多数票。七、这就是 Raft 对网络分区的处理例如Master1 Leader / \ / X ↓ ↓ Master2 Master3假设Master1 ↔ Master2 正常 Master1 ↔ Master3 断开 Master2 ↔ Master3 正常那么Master1 Master2仍然拥有2 / 3也就是多数派。所以Master1 Master2 仍然可以组成合法的 Raft 集群。而 Master3只有自己没有多数派1 / 3因此它不能成为 Leader也不能提交新的 Raft 日志。八、为什么 Raft 要求“多数派”因为多数派可以保证新 Leader和旧 Leader之间不会轻易产生冲突。对于 3 个节点Majority 2对于 5 个节点Majority 3例如3 节点 Master1 Master2 Master3 Master1 Master2 2 / 3 Majority但是Master3 1 / 3 MinorityMaster3 无法独立提交状态。九、网络分区是 Raft 非常重要的场景例如正常 Master1 Leader / \ M2 M3网络发生故障网络分区 │ X │ M1 M2 M3M1 M22 / 3拥有多数派。M31 / 3没有多数派。所以M1 M2 可以继续工作 M3 不能提交新的状态这就是 Raft 的一个非常重要的安全机制。十、旧 Leader 恢复之后怎么办这是理解 Raft 的另一个关键点。假设Term 10 Master1 Leader Master2 Follower Master3 FollowerMaster1 挂了。后来Term 11 Master2 Leader Master3 Follower然后 Master1 恢复。这时候Master1 旧 Leader Term 10重新连接集群。而 Master2Master2 当前 Leader Term 11Master1 会发现Term 11 Term 10于是Master1 必须承认自己已经不是 Leader。它会退回Follower变成Master2 Leader Master1 Follower Master3 Follower十一、Term 到底是什么Term 可以理解成Raft 的任期编号。例如Term 1 Term 2 Term 3 Term 4 ...每次发生新的 Leader ElectionTerm 1例如Term 10 Master1 LeaderMaster1 挂掉Term 11 Master2 Leader再挂Term 12 Master3 Leader因此Term是判断“谁更新”的重要依据。十二、“一个 Term 只能有一个 Leader”是什么意思例如Term 11在一个合法的 Raft 集群里Master1 Leader不能同时存在Master1 Leader Master2 Leader也就是说Term 11 最多一个 Leader但是Term 11 Term 12 Term 13每个 Term 都可能产生不同 LeaderTerm 11 → Master1 Term 12 → Master2 Term 13 → Master3所以并不是整个 Raft 集群生命周期只能有一个 Leader。而是同一个 Term 内最多只能有一个合法 Leader。十三、为什么旧 Leader 不会“复活夺权”假设Term 10 Master1 LeaderMaster1 挂了。然后Term 11 Master2 LeaderMaster1 恢复Master1 我是 Leader。Master2我的 Term 11 你的 Term 10Master1……然后 Master1 会降级为Follower原因就是Term 11 Term 10所以 Raft 中Term 是防止旧 Leader 复活后继续当 Leader 的重要机制。十四、旧 Leader 上可能还有一些“旧日志”怎么办这也是 Raft 最漂亮的设计之一。例如旧 LeaderMaster1曾经记录Term 10 Log: 1 2 3 4 5但是日志 5 还没有复制到多数节点。Master1 挂掉。新 LeaderMaster2可能只有Log: 1 2 3那么 Master1 恢复之后Master1 1 2 3 4 5Master21 2 3两者不一致。怎么办Raft 会让 Leader 对 Follower 进行日志同步。最终 Master11 2 3与当前 Leader 保持一致。旧的4 5会被覆盖/丢弃。所以旧 Leader 恢复后不是简单地“继续运行”而是先通过 Raft 日志复制重新追赶当前 Leader 的状态。十五、所有操作都是 Leader 做吗需要区分① 写操作通常是Client ↓ Leader ↓ Follower Follower也就是说Raft 的状态变更由 Leader 提议。例如创建 Volume 删除 Volume 修改配置 更新元数据这些状态变化通常由 Leader 发起。十六、Follower 完全不操作吗不是。Follower 不是“什么都不干”。Follower 至少要做这些事情1. 接收 Leader 心跳Leader │ ├── Heartbeat → Follower ├── Heartbeat → Follower └── Heartbeat → Follower2. 接收日志Leader │ │ AppendEntries ↓ Follower3. 保存日志Follower Log ├── entry 1 ├── entry 2 ├── entry 3 └── entry 44. 参与投票Leader 挂掉之后Follower ↓ Candidate然后参与 Leader Election。5. 参与提交Follower 收到日志后保存日志 ↓ 回复 Leader ↓ Leader 获得 Majority ↓ Commit所以 Follower 是 Raft 中非常重要的角色。十七、Raft 的写操作完整过程假设Master1 Leader Master2 Follower Master3 Follower客户端创建 Volume 1004Step 1客户端请求 LeaderClient ↓ Master1Step 2Leader 写入日志Master1 Log 1 2 3 4 ← Create Volume 1004Step 3复制给 FollowerMaster1 │ ├──→ Master2 │ └──→ Master3Step 4Follower 保存Master2 ✓ Master3 ✓Step 5获得多数派Master1 Master2 Master3 3 / 3满足MajorityStep 6CommitCreate Volume 1004正式提交。Step 7应用到状态机Raft Log ↓ State Machine ↓ Volume Metadata最终Master1 Volume 1004 ✓ Master2 Volume 1004 ✓ Master3 Volume 1004 ✓十八、Raft 的核心其实是“日志复制”理解 Raft 最重要的一个思维方式Raft 并不是直接同步最终状态而是同步“状态变化操作”。例如不要简单理解成Master1 当前 Volume 1004 同步给 Master2 Volume 1004而应该理解为Log 1. Create Volume 1001 2. Create Volume 1002 3. Delete Volume 1001 4. Create Volume 1003所有节点按照相同顺序执行这些操作Log ↓ State Machine ↓ 最终状态于是Master1 Log → State Master2 Log → State Master3 Log → State只要Log 一致最终状态就能够保持一致。十九、Raft 的三个核心模块可以把 Raft 简化成Raft │ ┌──────────┼──────────┐ ↓ ↓ ↓ Leader Election Log Replication Safety 领导选举 日志复制 一致性1. Leader Election解决Leader 挂了谁接替2. Log Replication解决Leader 的状态变化怎么同步给其他节点3. Safety解决如何避免出现两个 Leader、日志冲突、数据不一致二十、Leader Election 是怎么发生的假设M1 Leader M2 Follower M3 FollowerLeader 周期性发送Heartbeat例如M1 → M2 M1 → M3 M1 → M2 M1 → M3 M1 → M2 M1 → M3如果 M1 挂掉M2 长时间没收到 Heartbeat于是Follower ↓ CandidateTerm 增加Term 10 ↓ Term 11然后M2 → M3 RequestVote如果 M3 投票M2 Candidate M2 ✓ M3 ✓M2 获得2 / 3成为 LeaderTerm 11 M2 Leader M3 Follower二十一、为什么每个节点的 Election Timeout 不一样这是 Raft 避免多个节点同时发起选举的重要机制。假设M2 timeout 300ms M3 timeout 450msLeader 挂掉300ms M2 ↓ CandidateM2 比 M3 更早发起选举。这样可以降低M2 和 M3 同时竞选导致票数平分的概率。如果真的出现平票M21票 M31票就进入下一轮Term 1重新选举。二十二、Raft 如何防止一个旧 Leader继续写数据这是你理解 SeaweedFS Master 高可用时特别重要的一点。假设发生网络分区网络分区 X M1 M2 M3 LeaderM1 M22 / 3M31 / 3M3 即使认为M1 挂了也无法获得多数票。因此M3 不能成为合法 Leader更重要的是没有多数派就不能安全地提交新的 Raft 状态。这避免了两个网络分区同时各自修改状态最终产生两个互相冲突的集群。二十三、Raft 和 CAP 的关系Raft 经常和 CAP 一起讨论。网络分区发生时PartitionRaft 优先保证Consistency而不是让两个分区都继续写。例如2节点分区 M1 M2 M3M1 M2可以继续工作M3不能提交新的状态这意味着Raft 宁愿让少数派暂时不可写也不允许少数派产生可能与多数派冲突的新状态。二十四、3 节点 Raft 为什么通常比 2 节点好2 节点M1 M2如果 M1 挂了M2剩余1 / 2不是多数派。所以 M2 无法形成新的合法 Leader。而 3 节点M1 M2 M3挂一个M1 ❌ M2 M3剩余2 / 3仍然是 Majority。因此生产环境常见 3 节点或 5 节点 Raft 集群。二十五、Raft 和 SeaweedFS Master 的关系回到你正在研究的 SeaweedFS。可以把整体理解成SeaweedFS │ ┌───────────┴───────────┐ │ │ Master Cluster Volume Servers │ │ Raft 数据 │ │ ┌─────┼─────┐ ┌──────┼──────┐ ↓ ↓ ↓ ↓ ↓ ↓ M1 M2 M3 VS1 VS2 VS3 Leader Follower FollowerRaft 主要解决M1 M2 M3这些 Master 之间的状态一致性和 Leader 故障切换。而VS1 VS2 VS3真正负责大量文件/Volume 数据的存储。因此不要把Raft理解成“把所有 SeaweedFS 文件复制三份。”不是。更准确地说Raft ↓ Master 状态一致性而Volume Replication ↓ 业务数据副本这是两个完全不同的概念。二十六、把整个 Raft 过程串起来现在可以把你前面提出的几个问题全部串起来。正常情况M1 Leader / \ ↓ ↓ M2 M3 Follower FollowerM1Heartbeat ↓ M2 M3同时Client ↓ M1 ↓ Log Replication ↓ M2 / M3M1 挂掉M1 ❌ M2 M3等待 Election Timeout。例如 M2 先超时M2 ↓ Candidate ↓ Term 1 ↓ RequestVote ↓ M3 ↓ M2 获得 Majority ↓ M2 LeaderM1 恢复M1旧 TermM2新 TermM1 收到 M2 的消息发现 M2 Term 自己 Term于是M1 ↓ Follower然后 M2 把缺失的日志同步给 M1M2 Leader │ └──→ M1 Follower Sync Log最终M1 M2 M3 重新达到一致状态二十七、最终用一张图理解 RaftRaft Cluster │ ┌────────┴────────┐ │ │ Leader Followers │ │ ┌─────┴─────┐ ┌────┴────┐ │ │ │ │ ↓ ↓ ↓ ↓ Client Log复制 心跳 投票 │ │ │ │ ↓ ↓ │ │ Write请求 ─────→ Followers │ │ │ │ └────── Majority ──┘ │ │ │ ↓ │ Commit │ │ │ ↓ │ State Machine ←────────┘ │ ↓ 最终一致状态可以把 Raft 最终浓缩成5 句话Leader 负责协调和发起状态变更。Follower 接收日志、心跳并参与投票不是完全不做事情。Leader 挂掉后Follower 可以通过选举产生新的 Leader。任何状态变更必须获得多数派确认才能安全提交。旧 Leader 恢复后如果发现更高 Term会自动退回 Follower并从当前 Leader 同步缺失日志。而你提出的那个网络场景M1 Leader ├──→ M2正常 └──X M3断开 M2 ←→ M3正常不会因为 M3 收不到 M1 心跳就认为 M2 挂了。M3 只知道自己与 M1 的连接异常如果 M2 仍然能收到 M1 的心跳那么 M2 会继续认可 M1 是 LeaderM3 即使发起选举也无法获得多数票。这个设计正是 Raft 防止网络分区导致“双 Leader”的关键机制。
返回列表