这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天
课程内容与选题缘由
今天课程讲了分布式理论,其中我对RAFT分布式内容的协议比较感兴趣,为此结合课件的内容产出一篇RAFT的学习笔记
RAFT简介
RAFT协议是一种分布式系统共识算法,即使出现部分节点故障、网络延时等情况,也不影响各节点,从而提高系统的整体可用性。
在RAFT协议中,系统的节点有三种角色:
- 领导人(Leader):负责接收客户端请求,统一决策,并向其他Follower同步请求日志;当日志被同步到大多数节点后,通知Follower提交日志。
- 追随者(Follower):接收领导人同步的日志并进行提交。
- 候选人(Candidate):如果当前没有领导人,Follower可以变为候选人,请求其他节点投票。
在使用RAFT协议的系统中,有如下的重要环节帮助共识的达成:
- 领导人选举:当前没有领导人时,追随者会变为候选人,请求其他节点投票。如果一个候选人节点获得大多数节点的选票,则成为领导人。
- 日志复制:领导人向其他节点广播命令,其他节点将命令复制到本地日志。
Leader Election 领导人选举
RAFT网络中一开始所有的节点的角色都是Follower,为了产生一个节点可以领导整个网络进行日志状态的统一以及对外提供服务,因此需要有一个机制在网络中生成领导人节点,这个过程就是领导人选举。
如前面所提及,RAFT网络中的节点有三种角色,分别是
- Leader 领导人
- Follower 跟随着
- Candidate 候选者
每个节点都会维护一个计时器,计时器记录着一个名为election timeout的倒计时,election timeout被随机分配在150毫秒至300毫秒之间。当倒计时结束后,Follower跟随者成为Candidate候选者,并开始新的选举任期Term。
节点成为Candidate候选者后,会进入如下的流程:
- Candidate候选者首先为自己投一票,并向其他节点发送 Request Vote 请求投票消息
- Follower跟随者收到第一条有效的Request Vote请求投票消息后,将会为该Candidate候选者发送一条投票消息,并且重置其计时器,选举结果产生前不再接收新的Request Vote。
- 当前Candidate候选者如果收到了超过半数节点的同意,便会转变成Leader领导人节点,并使用Heartbeat心跳信息通知其他节点。
⚠️在Candidate候选者节点没有正式成为Leader之前,收到其他节点的Request Vote也要进行投票。
成为Leader领导人的节点,会向Followers发送指定时间间隔Heartbeat心跳信息重置Followers的定时器,维持领导人的位置。并且Append Entries 追加日志条目的消息也会通过Heartbeat心跳信息发给Follower。
该Leader领导人节点的选举任期将持续到 Follower追随者 因为没有收到新的Heartbeat心跳信息而重新成为Candidate候选人为止。
多重领导人情况(投票分裂)
在RAFT网络之中,一个Candidate候选者节点要获取大多数投票(半数)才能成为Leader领导者。但是可能存在一种情况,那就是有两个节点在相同的任期中,同时进行选举,并获得相同的投票。这种时候就会发生分裂投票的情况。
因此,当两个节点获得相同票数的情况下,所有节点都会进入等待选举超时的环节,在下一轮选举中再选出新的领导者。
重置计时器的情况
- 收到HeartBeat 心跳信息
- 收到Request Vote 投票信息
- 收到Term任期更高的Candidate候选者节点的Request Vote(投票分裂时)
分区恢复
不同网络分区中,会出现各个分区中都有一个Leader领导人节点,并维护各自的日志条目的情况。
当网络分区进行合并后,两个分区中的RAFT节点就要进行分区恢复:
- 分区合并后,两个分区中的节点会通过ping-pong消息确认分区恢复
- 确认分区合并后,所有节点都会进入选举流程
- 确认新的Leader领导人节点后,原来在另一个分区的Follower节点,会回滚其未提交的条目并匹配新领导者的日志。
在分区恢复的过程中,Leader领导人的日志不一定是其原来分区的日志,而一般是Term最新的日志数据。所有旧节点都需要同步新领导人的数据,Term比较旧的分区的日志数据会丢弃。
Stale Read
Stale read是指在RAFT协议的分布式系统中,客户端读取的数据不是最新的数据。
这种情况通常发生在节点间的数据同步没有完成之前,一个节点已经被更新了,但是另一个节点没有得到更新。当客户端读取不是最新的数据时,就产生了Stale read。
Stale Read可以使用如下机制避免:
- 在读请求中携带领导人的当前任期信息,并且如果读请求对应的Term任期比当前的Term任期旧,读请求将会被拒绝。
- 如果发生分区,节点将需要在读请求中等待更新的日志数据。在这种情况下,直到所有节点都同步完更新的日志,才允许读请求。
Log Replication 日志复制
找到一个RAFT算法的动态演示资源(Raft 分布式共识算法动画演示 (kailing.pub))
基于这个资源的动图我们对RAFT协议中的节点达成共识的过程进行梳理。
上面的动图是一个正常运行的Raft网络的工作流程和状态,绿色节点是外部请求服务的客户端。
Raft网络是常规的Master-Slave/Leader-Followers架构,图中的Node B便是Raft网络中的Leader节点,外部节点与Raft网络的交互主要通过与Leader节点通信来完成。
Raft的工作本质是对节点日志的维护,为了使网络中大部分节点都达到统一的日志状态,即拥有一模一样的日志记录,Leader需要通过两段式提交的方式与Followers进行日志条目的确认。
如上图所示:
- Node B接收到来自客户端的
SET 5请求后,会将此条目记录进入prepare状态,然后随着心跳信息将SET 5发送给Node A和C - A、C两个节点收到条目后会判断是否接受此条目,如果接受则也将此条目记录并进入prepare状态,然后回复Node B
- Node B在接收到大部分节点回复的确认后,将会把记录的条目commit,然后回复绿色的客户端,同时也将发送commit信息给所有的Followers
- Followers接收到后,也会相应将
SET 5条目commit
至此,网络中所有节点的日志状态都达到了一致。