Raft 协议是一种为了管理分布式系统的日志复制而设计的一致性算法,Raft的目标是提供一种比 Paxos 更容易理解和实现的方式来保证分布式系统的一致性。Raft 被广泛用于分布式系统中,例如:Etcd、Consul、Nacos、RocketMQ、Redis Sentinel等底层都是采用Raft算法选举主节点。
Raft 协议的核心概念
Raft 将整个协议分解为几个子问题:领导者选举(Leader Election)、日志复制(Log Replication)、安全性(Safety)、以及更少讨论的成员变更(Membership Changes)。这样的分解使得算法的每一部分都相对简单易懂。
Raft算法通过以下三个主要子问题来实现一致性:
- Leader选举(Leader Election): 在集群中选举出一个Leader来管理日志复制。
- 日志复制(Log Replication): Leader将日志条目复制到其他所有服务器。
- 安全性(Safety): 确保所有已提交的日志条目不会被覆盖,且所有服务器上已提交的日志条目最终一致。
Raft 中的角色
在 Raft 协议中,集群中的每个节点可能处于以下三种状态之一:
- 领导者(Leader) :处理客户端请求并管理日志复制。
- 跟随者(Follower) :被动的响应来自领导者和候选者的请求。
- 候选者(Candidate) :用于领导者选举。
Raft算法的主要RPC
Raft算法主要使用两种RPC:
-
RequestVote RPC(请求投票):
- 候选者发送:在选举期间,候选者向其他服务器发送RequestVote请求,试图获得选票。
- 响应:服务器根据当前状态和日志决定是否投票。
-
AppendEntries RPC(追加日志):
- Leader发送:Leader定期发送心跳或日志条目到Followers。
- 响应:Followers确认接收日志条目并返回响应。
Raft 的工作流程
领导者选举
- 触发选举:所有节点都以跟随者的身份启动,每个跟随者都有一个随机的选举超时时间,避免所有跟随者同时发起投票请求。如果跟随者在选举超时时间内没有收到领导者的心跳或者请求,它会认为领导者已经崩溃,然后将状态转变为候选者并开始新一轮的选举。
- 投票过程:
-
- 候选者在选举超时后开始发起投票,首先增加自己的任期号(Term Number),先给自己投一票,并向其他服务器发送RequestVote(请求投票)请求。
- 其他服务器收到RequestVote请求后,根据当前状态和日志决定是否投票,并增加自己的任期号。
- 当候选者收到多数服务器的投票后,它将成为新的Leader。
- Leader节点每隔一段时间会向所有跟随者发送心跳请求。
- 超时与重试:如果选举过程在超时时间内没有决出胜者,候选者会增加其当前的任期号(Term Number),并开始新一轮的选举。
日志复制
Leader负责处理客户端请求并将日志条目复制到其他服务器:
- 领导者接收客户端请求:每个客户端请求包含一条需要系统执行的命令。
- 追加日志:领导者先将命令作为新的日志条目追加到自己的日志中。
- 复制日志: 领导者通过AppendEntries RPC将日志复制到所有跟随者。
- 日志提交:当日志复制到大多数节点上后,该日志被标记为已提交,并通知跟随者提交日志,然后领导者通知客户端操作已完成。
一致性检查
Raft算法通过任期号和日志匹配来确保一致性:
- 任期号: 每个日志条目都带有一个任期号,确保新Leader的日志是最新的。
- 日志匹配: AppendEntries RPC请求包含前一个日志条目的索引和任期号,Follower只有在其日志与Leader的日志匹配时才会接受新的日志条目。
安全性
Raft算法确保所有已提交的日志条目不会被覆盖,并且所有服务器最终一致:
- 日志一致性: Raft算法确保已提交的日志在所有服务器上最终一致,即使在发生网络分区的情况下。
- Leader变更: 新的Leader必须拥有所有已提交的日志,这通过在选举过程中检查日志匹配来实现。
- 任期概念:每个日志都有任期号,用以区分不同领导者的命令,以防止过时的领导者覆盖新的日志条目。
成员变更
- 配置变更:Raft 可以在不停机的情况下改变其集群配置,包括添加和移除服务器。
- 联合共识:在变更期间,系统通过联合多个配置的共识来保持持续的操作。
优势
Raft 通过将复杂的一致性问题分解成几个关键子问题,并提供了清晰的解决方案,从而提供了一种既健壮又易于理解的分布式系统一致性算法。