Raft算法之集群成员变化篇

1、集群成员变化可能带来的问题算法

集群成员变化是一个常见操做,主要是增长、删除节点,主要的场景有升级、服务器老化等,固然若是咱们对服务的SLA没太大要求,直接关闭集群是最简单的办法。但若是要保证系统的可用性而动态地添加、删除节点而且保证不会脑裂等问题则须要一个安全的算法,因此Raft算法把这一部分也归入其中。安全

直接将集群成员配置从旧配置切到新配置会有脑裂问题,举个例子:服务器

Raft算法之集群成员变化篇

上图中集群原来有3个节点:Server一、Server二、Server3,如今要增长2个节点:Server四、Server5,咱们来设想下具体的操做步骤:spa

一、Server4和Server5是新节点,因此这2台机器启动的时候认为集群中有5个节点;日志

二、而后修改Server3的配置,改为5节点;blog

这时发生选举,即上图中红色箭头所指的位置,这时候每一个节点看到的集群成员以下,为了方便描述,统一将Server字样去掉,即只保留一、二、三、四、5,1表示Server1:rem

1:一、二、3同步

2:一、二、3it

3:一、二、三、四、5class

4:一、二、三、四、5

5:一、二、三、四、5

这时1经过2的投票能够被选举为Leader,由于1和2认为集群只有一、二、3总共3个节点;

3经过3,4,5这3个节点的投票被选举为Leader;

这样集群同时存在1和3两个Leader了。

2、变动方案

官方给的方案是二阶段变动:

集群先从旧成员配置Cold切换到一个过渡成员配置,称为共同一致(joint consensus),共同一致是旧成员配置Cold和新成员配置Cnew的组合Cold U Cnew,一旦共同一致Cold U Cnew被提交,系统再切换到新成员配置Cnew。

具体过程以下:

Leader收到从Cold切成Cnew的成员变动请求,Leader分两步操做:

一、提交配置Cold U Cnew

Leader在本地生成一个新的日志,这个日志的类型是成员配置,其内容是Cold∪Cnew,表明当前时刻新旧成员配置共存,写入本地日志,但并不提交;

Leader同时将该日志复制至Cold∪Cnew中的全部副本,在此以后新的日志同步须要保证获得Cold和Cnew两个多数派的确认;

Follower收到Cold∪Cnew的日志后更新本地日志,而且立刻就以该配置做为本身的成员配置;

若是Cold和Cnew中的两个多数派确认了Cold U Cnew这条日志,Leader就提交这条日志;

二、提交Cnew

接下来Leader生成一条新的日志条目,类型也是成员变动,其内容是新成员配置Cnew,一样将该日志条目先写入本地日志,同时复制到Follower上;

Follower收到新成员配置Cnew后,将其写入日志,而且立刻就以该配置做为本身的成员配置,而且若是发现本身不在Cnew这个成员配置中会自动退出。

能够看到,Raft算法将成员配置的变化也做为一条日志,须要通过一轮Raft过程像应用操做同样只要大多数节点确认了就确定不会出出脑裂了。注意Follower收到配置后立刻就变动,而不须要等Leader下次发送commitIndex的时候才提交,这点是和正常应用提交不同的地方。

这里不去作详细的证实,官方有详细说明,咱们能够看下几个异常,仍是以上面的例子,当前集群有3个节点:一、二、3,如今要增长2个节点:四、5,假设当前Leader为1,具体过程以下:

1)节点1收到成员变动的请求,生成一条日志类型为成员变动,内容为:一、二、三、四、5,节点1将这条日志先保存到本地,但不立刻更改为员配置;

2)节点1将上述日志同步给2,3,4,5四个节点;

3)二、三、四、5节点收到配置后作2件事:追加日志,立刻变动本身的成员配置为:一、二、三、四、5;

4)节点1只要收到2个以上节点回复立刻将本身成员配置为:一、二、三、四、5.

咱们看有哪些异常:

若是有1-2过程当中失败了,则整个过程就算失败,则须要管理员从新发起成员变动操做;

若是第3步只有1个节点即不是集群多数节点收到变动,这个时候节点1挂了,若是收到日志的先发起选举则有可能推动这条日志,不然就不成功,即有可能丢失;

若是在第4步节点1挂了的话,新集群确定是有这个配置的,由于根据日志最新原则,新选举出来的Leader确定包含上面成员变动的日志。

3、其它问题

一、新加的成员入无日志

一开始的时候新的服务器可能没有任何日志条目,若是它们在这个状态下加入到集群中,那么它们须要一段时间来更新追赶,在这个阶段它们还不能提交新的日志条目,这个时候节点没有投票权,有的文章说叫Catch-Up。

二、移除不在 Cnew 中的服务器可能会扰乱集群

主要是移除的状况,设想一个集群有5个节点:1,2,3,4,当前Leader是2,如今要把1移除掉,假如2已经将新的成员配置:2,3,4已经同 步给3和4了,若是配置不发给1,由于2认为集群中1不存在了,因此不会向1发心跳,而1没收到2的心跳,会增长本身的Term发起选举,其它成员收到后会退化成Follower,不过不会给1投票,由于1的日志不是最新的,不过这会影响集群的可用性。

针对这个问题,官方给的是PreVote,即在发起投票的RequestVote RPC请求以前再发一个PreVote请求,只有经过这个才正式发起RequestVote,这样能够大大提高系统的可用性。其实还有1个更简单的办法,直接将1关机或者将服务程序Kill掉。

image.png

相关文章
相关标签/搜索