分布式算法 —— Raft算法
分布式算法 - Raft算法
Raft算法
算法简介
不同于Paxos算法直接从分布式一致性问题出发推导出来,Raft算法则是从多副本状态机的角度提出,用于管理多副本状态机的日志复制。Raft实现了和Paxos相同的功能,它将一致性分解为多个子问题:Leader选举(Leader election)、日志同步(Log replication)、安全性(Safety)、日志压缩(Log compaction)、成员变更(Membership change)等。同时,Raft算法使用了更强的假设来减少了需要考虑的状态,使之变的易于理解和实现。
学习推荐
角色
角色划分
Raft将系统中的角色分为领导者(Leader)、跟从者(Follower)和候选人(Candidate):
- 领导者(Leader):接受客户端请求,并向Follower同步请求日志,当日志同步到大多数节点上后告诉Follower提交日志。
- 跟从者(Follower):接受并持久化Leader同步的日志,在Leader告之日志可以提交之后,提交日志。
- 候选人(Candidate):Leader选举过程中的临时角色。
角色的状态转换
Follower只响应其他服务器的请求。
如果Follower超时没有收到Leader的消息,它会成为一个Candidate并且开始一次Leader选举。
收到大多数服务器投票的Candidate会成为新的Leader。
Leader在宕机之前会一直保持Leader的状态。
Raft算法将时间分为一个个的任期(term),每一个term的开始都是Leader选举。
在成功选举Leader之后,Leader会在整个term内管理整个集群。如果Leader选举失败,该term就会因为没有Leader而结束。
Leader选举
Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时,初始化为Follower。Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会等待一段随机的时间后发起一次Leader选举。
Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送 RequestVote RPC,结果有以下三种情况:
- 赢得了多数的选票,成功选举为Leader;
- 收到了Leader的消息,表示有其它服务器已经抢先当选了Leader;
- 没有服务器赢得多数的选票,Leader选举失败,等待选举时间超时后发起下一次选举。
选举出Leader后,Leader通过定期向所有Followers发送心跳信息维持其统治。若Follower一段时间未收到Leader的心跳则认为Leader可能已经挂了,再次发起Leader选举过程。
日志同步
Leader选出后,就开始接收客户端的请求。
Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他服务器发起 AppendEntries RPC复制日志条目。
当这条日志被复制到大多数服务器上,Leader将这条日志应用到它的状态机并向客户端返回执行结果。
某些Followers可能没有成功的复制日志,Leader会无限的重试 AppendEntries RPC直到所有的Followers最终存储了所有的日志条目。
当系统(leader)收到一个来自客户端的写请求,到返回给客户端,整个过程从leader的视角来看会经历以下步骤:
- Leader追加日志条目
- Leader并行发布AppendEntries RPC
- Leader等待多数的回应
- Leader将条目应用到状态机
- Leader回复Client
- Leader通知Follwers应用日志
日志在某个节点状态如下:
不难看出,logs由顺序编号的log entry组成 ,每个log entry除了包含command,还包含产生该log entry时的leader term。从上图可以看到,五个节点的日志并不完全一致,raft算法为了保证高可用,并不是强一致性,而是最终一致性,leader会不断尝试给follower发log entries,直到所有节点的log entries都相同。
安全性
如果节点将某一位置的log entry应用到了状态机,那么其他节点在同一位置不能应用不同的日志。简单点来说,所有节点在同一位置(index in log entries)应该应用同样的日志。但是似乎有某些情况会违背这个原则:
阶段A:S1成为Leader,在term2提交的日志赋值到了S1、S2两个节点;
阶段B:S1下线了,重新进行Leader的选举,S5成为了term 3的Leader;
阶段C:S5尚未将日志推送到Followers就离线了,S1重新上线后被选举为term 4的Leader,此时S1会将自己的日志同步到Followers;
阶段D:S1又一次下线,触发一次选主,而S5有可能被选为新的Leader(term = 5 > 4且有最新的日志),然后S5会将自己的日志更新到Followers,于是S2、S3中已经被提交的日志(2,2)被截断了。
为了避免上面的情况,添加以下限制:
- 拥有最新的已提交的log entry的Follower才有资格成为Leader。
这个保证是在RequestVote RPC中做的,Candidate在发送RequestVote RPC时,要带上自己的最后一条日志的term和log index,其他节点收到消息时,如果发现自己的日志比请求中携带的更新,则拒绝投票。日志比较的原则是,如果本地的最后一条log entry的term更大,则term大的更新,如果term一样大,则log index更大的更新。
- Leader只能推进commit index来提交当前term的已经复制到大多数服务器上的日志,旧term日志的提交要等到提交当前term的日志来间接提交(log index 小于 commit index的日志被间接提交)。
日志压缩
在实际的系统中,不能让日志无限增长,否则系统重启时需要花很长的时间进行回放,从而影响可用性。Raft采用对整个系统进行snapshot来解决,snapshot之前的日志都可以丢弃。
每个副本独立的对自己的系统状态进行snapshot,并且只能对已经提交的日志记录进行snapshot。
Snapshot中包含以下内容:
- 日志元数据。最后一条已提交的 log entry的 log index和term。这两个值在snapshot之后的第一条log entry的AppendEntries RPC的完整性检查的时候会被用上。
- 系统当前状态。
当Leader要发给某个日志落后太多的Follower的log entry被丢弃,Leader会将snapshot发给Follower。或者当新加进一台机器时,也会发送snapshot给它。发送snapshot使用InstalledSnapshot RPC。
做snapshot既不要做的太频繁,否则消耗磁盘带宽, 也不要做的太不频繁,否则一旦节点重启需要回放大量日志,影响可用性。推荐当日志达到某个固定的大小做一次snapshot。
做一次snapshot可能耗时过长,会影响正常日志同步。可以通过使用copy-on-write技术避免snapshot过程影响正常日志同步。
成员变更
什么是成员变更
成员变更指的是系统成员变化,即服务器节点的上下线,这和由于宕机故障导致的上下线是不同的。宕机或者重启导致的上下线,是不会影响系统的注册的成员数量的,也就不会影响到一致性判断所依据的“多数派”的生成,众所周知,“多数派”是所有一致性的基础。成员变更时,会修改注册的成员数量,比如在实际应用中,为了提高安全等级,就很可能出现需要把备机数量由三台扩充到五台,在这种情况下,就发生了成员变更。
Raft成员变更实现
Raft提出了通过一个中间过渡阶段,即联合共识(joint consensus),逐步把数据写入的新的集群中。其具体做法是2阶段提交式的:
第一阶段:先写一条{Cold, Cnew}同步到新旧两个集群的多数派,写入这条日志后,系统中的任何写入请求,都要同步到Cold和Cnew两个集群的多数派才算写入成功
第二阶段:当{Cold, Cnew}同步成功后,再写一条Cnew,同步给新集群,然后就可以完成切换了。
这个过程看起来比较复杂,其实从宏观来理解,可以把Cnew看作原有集群的一个热备,在联合共识阶段,一个请求要写入原有系统和热备,之后,不论{Cold, Cnew}这条日志是否写成功到多数派,不论热备出现了何种故障,原有系统会一直保证数据是一致的。当写入Cnew到多数派备机成功后,就保证了新集群和热备有了一致且完备的数据,在这种情况下,新集群就可以接替原有集群工作了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!