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(
prevLogIndex
和prevLogTerm
)、要追加的日志条目(entries
)、Leader 的提交索引(leaderCommit
)等信息。
4.2 Followers 收到 AppendEntries
RPC
- Followers 首先检查
prevLogIndex
和prevLogTerm
,即 Leader 的上一个日志条目的索引和 term 是否与自己的日志匹配。如果不匹配,说明 Leader 和 Follower 的日志不一致,可能是由于 Leader 发送的 RPC 之前发生了日志的复制失败或其他问题。
4.3 一致性检查
- 如果
prevLogIndex
和prevLogTerm
匹配,那么 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: 恋水无意
腾讯云开发者社区:孟斯特