1. Raft 简介

Raft 是一种共识算法,它确保在分布式系统中的多个节点之间达成一致性。Raft 的核心目标之一是保证数据在所有节点之间的同步。以下是 Raft 如何同步数据的主要步骤:

1.1 Leader 选举

  • Raft 将所有节点分为三种角色:Leader(领导者)、Follower(追随者)、Candidate(候选者)。
  • 在初始状态或者当 Leader 失效时,节点会进入选举阶段,各节点会竞选成为新的 Leader。
  • 通过投票的方式,最终获得超过半数的节点的支持的节点成为新的 Leader。

1.2 日志复制

  • Leader 负责接收客户端的写请求,并将这些写请求以日志条目的形式追加到自己的日志中。
  • 一旦 Leader 收到一条新的日志条目,它会将这个条目发送给所有的 Follower 节点。

1.3 提交日志

  • 当 Leader 发送一条日志给 Follower 后,需要等待超过半数的节点都复制了这个日志,Leader 才会将该日志标记为“已提交”。
  • 一旦一条日志被提交,Leader 会通知所有节点该条目已经被提交,这时节点可以将这个日志应用到它们的状态机中。

1.4 心跳机制

  • Leader 定期向所有 Follower 发送心跳消息,以保持其领导地位。
  • 如果一个 Follower 在一定时间内没有收到 Leader 的心跳消息,它会触发新一轮的选举。

1.5 持久化

  • Raft 保证所有的日志条目都会被持久化到存储介质中,以便在节点重启后能够重新加载。

1.6 数据同步的一致性

  • 通过 Leader 的中介,确保了所有的节点都复制了相同的日志条目,从而保持了系统的一致性。

2. 通信

在 Raft 算法中,各节点之间通过 RPC(远程过程调用)进行通信。以下是 Raft 中节点之间的主要通信方式:

2.1 请求投票 RPC(RequestVote RPC)

  • 在选举过程中,候选者节点会向其他节点发送请求投票的 RPC。
  • 请求投票包括候选者的选举 term、候选者的 ID、候选者的最后日志条目的索引和任期。
  • 节点在收到请求投票 RPC 后,会检查候选者的信息,并根据自己的状态判断是否投票给该候选者。

2.2 附加日志条目 RPC(AppendEntries RPC)

  • Leader 节点负责将新的日志条目发送给 Followers,以保持日志的一致性。
  • 附加日志条目 RPC 包括 Leader 的 term、Leader 的 ID、日志条目等信息。
  • Followers 收到附加日志条目 RPC 后,会检查 Leader 的信息,如果信息正确,就将日志条目追加到自己的日志中。

2.3 心跳 RPC

  • Leader 会定期向 Followers 发送心跳 RPC,以保持对 Leader 的认可。
  • 心跳 RPC 实际上是一种特殊的附加日志条目 RPC,其不包含日志内容,仅用于维持 Leader 与 Followers 之间的连接。
  • 如果一个 Follower 在一定时间内没有收到 Leader 的心跳,就可能触发新一轮的选举。

这些 RPC 的使用使得 Raft 算法中的节点能够协调完成选举、同步日志等任务。需要注意的是,Raft 通过使用 RPC 确保了消息的有序传递,确保了一致性和可靠性。在实际实现中,这些 RPC 的细节通常会被封装在网络库或通信层中,以简化 Raft 算法的实现。

3. Leader选举

Raft 算法选举 Leader 的过程是确保分布式系统中只有一个 Leader 负责写操作的关键机制之一。以下是 Raft 选举 Leader 的实现细节:

3.1 选举触发条件

  • 在 Raft 中,每个节点都有一个当前的 term(任期)。
  • 当一个节点启动时,它的 term 被初始化为 0。
  • 每个 term 都有一个唯一的标识符,用于区分不同的选举和日志追加阶段。
  • 当一个节点发现自己的 term 超过了当前系统中节点的最大 term,它会变成 Candidate 并开始新一轮的选举。

3.2 成为 Candidate

  • 节点变成 Candidate 后,它会增加当前 term,并将自己的状态切换为 Candidate。
  • 然后,它会向其他节点发送请求投票的 RPC。

3.3 请求投票 RPC(RequestVote RPC)

  • Candidate 向其他节点发送请求投票的 RPC,包含自己的 term、ID 以及自己的最后一条日志的 term 和索引。
  • 如果接收到请求投票的节点发现 Candidate 的 term 大于自己的 term,它会更新自己的 term,并投票给 Candidate。
  • 节点投票给 Candidate 的条件通常是 Candidate 的日志比自己的新,或者两者的日志相同时,选择 term 较大的 Candidate。

3.4 获得多数票

  • Candidate 需要获得超过半数的节点的投票,以确保在当前 term 成为 Leader。
  • 一旦 Candidate 获得了多数票,它将变成 Leader,并开始发送心跳 RPC 维持其 Leader 地位。

3.5 心跳机制

  • Leader 定期向其他节点发送心跳 RPC,以保持其 Leader 地位。
  • 如果其他节点在一段时间内没有收到 Leader 的心跳,它们可能会认为 Leader 失效,触发新一轮的选举。

3.6 避免脑裂(Split Vote)

  • Raft 算法通过在选举时引入随机的等待时间,避免了脑裂问题,即多个节点同时发起选举,形成没有明确的 Leader 的状态。
  • 在发起选举后,Candidate 会等待一个随机的时间再开始下一轮选举,从而减少同时发起选举的可能性。

以上是 Raft 算法选举 Leader 的基本流程。这种基于票数的选举机制确保了系统中只有一个 Leader 负责写操作,从而维护了一致性。

4. AppendEntries的一致性检查

在 Raft 中,AppendEntries 是 Leader 用来将日志条目追加到 Followers 上的追加日志 RPC。一致性检查在 AppendEntries 中的实现是为了确保 Leader 和 Followers 的日志保持一致。这个一致性检查的关键是 Leader 需要向 Followers 提供足够的信息,以便 Followers 可以正确地匹配 Leader 的日志。

以下是 AppendEntries 中的一致性检查的一般过程:

4.1 Leader 向 Followers 发送 AppendEntries RPC

  • 这个 RPC 包含了 Leader 当前的 term、Leader ID、Leader 的上一个日志条目的索引和 term(prevLogIndexprevLogTerm)、要追加的日志条目(entries)、Leader 的提交索引(leaderCommit)等信息。

4.2 Followers 收到 AppendEntries RPC

  • Followers 首先检查 prevLogIndexprevLogTerm,即 Leader 的上一个日志条目的索引和 term 是否与自己的日志匹配。如果不匹配,说明 Leader 和 Follower 的日志不一致,可能是由于 Leader 发送的 RPC 之前发生了日志的复制失败或其他问题。

4.3 一致性检查

  • 如果 prevLogIndexprevLogTerm 匹配,那么 Followers 开始检查要追加的日志条目。
  • Followers 需要确保 Leader 发送的日志条目与自己的日志保持一致。这包括比较 Leader 发送的每一条日志条目的 term 和索引。如果某个条目不匹配,Followers 会拒绝追加,Leader 需要回退自己的 nextIndex,然后重新发送 AppendEntries

4.4 应用日志

  • 一致性检查通过后,Followers 将 Leader 发送的日志条目追加到自己的日志中。如果 Leader 提交的索引大于 Followers 当前的提交索引,Followers 将自己的提交索引更新为 Leader 的提交索引。

4.5 Leader 等待响应

  • Leader 等待 Followers 对 AppendEntries 的响应。如果 Followers 成功追加了日志,它会返回成功的响应,Leader 可以继续处理下一个日志条目。如果失败,Leader 需要根据 Followers 提供的信息调整自己的 nextIndex

这种一致性检查确保了 Leader 和 Followers 之间的日志保持一致,即使在网络分区或者节点宕机的情况下,也能够正确地进行日志的同步。


孟斯特

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特