Raft
leader-based的共识算法
raft会先选出leader,leader完全负责replicated log的管理。leader负责接受所有客户端更新请求,然后复制到follower节点,并在安全的时候执行这些请求。如果leader故障,follower会重新选出新的leader
是一种实现分布式一致性的协议。
节点状态
- Follower 请求的被动更新者,从Leader接受更新请求,写入本地日志文件
- Candidate 如果Follower副本在一段时间内都没有收到Leader副本的心跳,则判断Leader可能已经故障,此时启动选主过程,该副本变成Candidate,直到选主结束
- Leader 所有请求的处理者,Leader副本接受client的更新请求,本地处理后再同步至多个其他副本
Leader Election
Leader选举
所有节点启动时都是follower状态;
在一段时间内如果没收到来自leader的心跳,从follower切换到candidate,发起选举;
如果收到majority的选票(含自己的一票)则切换到leader状态;
如果发现其他节点比自己更新,则主动切换到follower
系统中最多只有一个leader,如果在一段时间里没发现leader,则大家通过投票选出leader。leader会不停的给follower发心跳消息,表明自己的存活状态。如果leader故障,那么follower会转换成candidate,重新选出leader。
如果出现平票的情况,那么就延长系统不可用的时间(没有leader就无法处理客户端写请求),因此raft引入了randomized election timeouts来尽量避免平票情况

-
节点一开始是follower状态
初始化
-
如果followers没有收到来自leader的信息,变成candidate
follower->candidate
-
candidate向其他节点请求投票
请求投票
-
节点响应投票
响应投票
-
candidate如果获取到大多数节点的投票,就成为leader
成为leader
Log Replication
日志复制
客户端的一切请求发送到leader,leader来调度这些并发请求的顺序,并且保证leader与follower状态的一致性。raft的做法是将这些请求以及执行顺序告知followers。leader和followers以相同的顺序来执行这些请求,保证状态一致。
-
对系统的所有更改现在将通过leader。
每个改变作为一个entry加入到node的日志里。
日志entry当前是未提交状态,所以不会更新节点的值
向leader发起更改
-
为了提交entry,节点首先将它复制到follower节点
日志复制
-
leader等待大多数节点写入entry。
现在leader上已经提交了entry,节点状态是“5”
多数节点写入了entry
-
leader通知followers,entry已经提交。
集群现在已经就系统状态达成一致
通知followers提交entry
Leader选举详细过程
在Raft中,有两种timeout设置来控制选举
第一个是election timeout
follower成为candidate前所需等待的时间。选举超时随机设置为150ms~300ms
-
超过election timeout后,follower成为candidate,开启一个新的选举任期(term)。
投票给自己,发送请求投票(Request Vote)消息给其他节点
超时后成为候选者
向其他节点发送请求投票
-
如果接收节点在此期间尚未投票,它会投票给这个candidate。
接收节点重置它的election timeout
投票给candidate
-
一旦一个candidate有多数的投票,它就成为leader
candidate成为leader
- leader开始发送Append Entries消息给它的followers
这些消息按heartbeat timetout的间隔来发送
leader发送心跳消息
-
然后Followers响应每个Append Entries消息
这一选举任期(term)会持续直到一个follower停止接收心跳并成为candidate
followers响应消息
停掉leader,重新选举
-
节点C是任期(term)2的leader
需要多数投票才能保证在每个任期里只有一个leader被选举出来
如果有两个节点同时成为candidate,则可能会发生分离投票
任期2,节点C是leader
-
两个节点在相同任期(term)里同时开始启动选举
每个在另一个之前到达一个follower
现在每个candidate有两票,且在本任期内不能接收到更多选票
此时候选者会等待选举超时,然后发起新一轮选举
两个节点同时启动选举
每个分别先到达一个follower
-
这时候新的一轮,节点C接受了多数投票,成为leader
新一轮投票选出leader
日志复制详细过程
一旦选出了一个leader,就需要将系统的所有更改复制到所有节点
这是通过使用与心跳相同的Append Entries消息来完成。
-
首先客户端发送一个变更到leader
此变更被追加到leader的日志
客户端发送变更
-
此变更在下一次心跳的时候发送到followers
发送变更到followers
follower追加日志
-
一旦多数followers响应,entry被提交。响应发送给客户端
响应发给客户端
-
客户端发送增加2的变更,系统值被更新为“7”
系统值变更
网络分区
raft也能在网络分区的情况下保持一致性
-
网络分区产生
产生网络分区
-
现在有两个不同的leader在不同的任期(term)内
两个任期,两个leader
-
增加一个客户端,一个客户端尝试将节点B的值设置为“3”
节点B不能复制到多数节点,所以日志entry保持未提交状态
节点B尝试设置为3
-
另一个客户端尝试设置节点C的值为“8”
此时将成功,因为可以复制到多数节点
节点C尝试设置为8
-
修复网络分区
节点B将看到更高的选举任期并下台
此时节点A和B将回滚未提交的entries,匹配新的leader的日志
此时集群里的日志将保持一致
修复网络分区,节点B下台
网友评论