Raft一致性算法

今天和明天都得值班,基本主要是看监控,趁着空闲时候大概看了会raft算法,以前比较粗略的了解了一下,今天仔细的学习了会,在这里做个笔记吧。

在分布式系统中,一致性是个很棘手的问题,单节点没有这个问题,但是为了保证高可用,往往会多机房部署,这样每个服务的一致性就必须得保证,raft一致性算法就是为了解决这个问题。

在Raft中,每个服务都有三个角色:

  • Follower
  • Candidate
  • Leader

这三个角色可以互相转换,下面我们从正常的流程走下去,把整个流程梳理一遍。

初始

假设我们部署了四个节点(A,B,C,D),那么每个节点的初始角色都是Follower。同时每个节点都有一个定时器,该定时器主要是为了判断Leader节点异常的设置的,当定时器超时后,Follower就认为Leader已经生效。

选举

首先先引入term这个词,每一轮的选举,都有一个election term的值,用于标志那一轮的选举,这个值是为了防止其余节点重复投票而设置的。

在Follower角色的每个节点,待定时器超时后,会发起一次选举,同时为自己投一票。发起选举的节点的election term值会增加1,同时角色转为Candidate。假设当前的值为1,那么其余节点收到了投票请求后,会设置当前的election term,同时给发起请求的节点投一票,当整个集群中有半数以上(N/2+1)的节点投了赞成票后,那么该节点就会成为Leader,同时不断的发送heartbeat来重置其余节点的选举定时器。

上述是只有一个节点发起选举的情形,一般每个节点的选举超时都在150-300ms之间,所以很少会同时发起选举,可是当有2个节点同时发起选举呢?

假设这儿A和B节点同时发起了投票,那么A和B的election term都为1,发起了term为1的投票,假设A获取了大部分的票数,那么A成为了Leader,B发现自己的票数不足,则转为Follower,这是我们希望看到的情况。但是假设A获得了2票,而B也货到了两票呢?这样就发生了Splite Vote的情形。

针对 Split Vote 情形,则本轮投票失败,Candidate角色转为Follower角色,等待下一轮的选举。由于定时器都是随机的,几个节点同时发起投票的概率是很低的。

election term保证投票节点在同一个term下,只会投票一次,对于相同term的其余投票,则不会继续投。

日志复制

进入这一步后,我们应该有且仅有一个Leader节点了。客户端的请求只会发往Leader,Follower不会直接处理用户的请求,当用户执行了一个命令后,Leader首先会在本节点写入一条日志,但是还没有提交(生效),并把该日志推向Follower,Follower收到该日志后,则会写入该日志,但是也不会提交(生效),同时向Leader确认。

当Leader收到了半数以上的Follower的回应后,则会提交该日志,使该操作生效,同时回应客户端操作完成,也会将Commit下发到Follower,这样Follower也将应用该日志使其生效。

同步情况下,也有一种特殊的情况,就是因为网络原因,使集群部分节点断开,比如A和B成为了一组,CDE成为了一组。在此情况下,CDE会选举出新的Leader,此时会有比AB组更新的term。

假设此时AB组的term为1,CDE组的term为2,当客户端给AB组的Leader A发送了某个操作后,按照上述的流程,在日志同步到了B后,B确认,但是仅仅只有B确认,没有达到大部分的节点确认,那么该操作仅仅是append进去,没有真正的commit,当该操作到了CDE组的Leader C后,那么由于CDE组有3个节点,那么该操作生效,于是该操作完成了。

当网络恢复后,所有节点都在一个组内后,发现了有2个Leader,所以必须得由一个Leader失效转换为Follower的角色。2个Leader会根据哪个Leader的election term值最大而判别哪个Leader是最终的Leader,而另一个Leader,会把未Commit的log进行rollback,同时接受来自当前Leader的同步,于是整个集群又恢复到了一致性的状态。

其实这里还有一种情形,那就是ABC与DE分割了,其实这也很简单,DE根本无法选举出Leader,那么DE将始终处于Candidate角色,当集群恢复后,DB会接受Leader的同步。

尾巴了

大致的流程就是按上述的流程来走,自己也只是梳理了个大概,推荐大家可以看The secret lives of data的动画来明白其中的思想。

共 0 条回复
暂时没有人回复哦,赶紧抢沙发
发表新回复

作者

sryan
today is a good day