前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Raft算法之集群成员变化篇

Raft算法之集群成员变化篇

作者头像
心平气和
发布2020-11-03 15:40:31
9020
发布2020-11-03 15:40:31
举报

一、集群成员变化可能带来的问题

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

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

上图中集群原来有3个节点:Server1、Server2、Server3,现在要增加2个节点:Server4、Server5,我们来设想下具体的操作步骤:

1、Server4和Server5是新节点,所以这2台机器启动的时候认为集群中有5个节点;

2、然后修改Server3的配置,改成5节点;

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

1:1、2、3

2:1、2、3

3:1、2、3、4、5

4:1、2、3、4、5

5:1、2、3、4、5

这时1通过2的投票可以被选举为Leader,因为1和2认为集群只有1、2、3总共3个节点;

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

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

二、变更方案

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

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

具体过程如下:

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

1、提交配置Cold U Cnew

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

Leader同时将该日志复制至Cold∪Cnew中的所有副本,在此之后新的日志同步需要保证得到Cold和Cnew两个多数派的确认;

Follower收到Cold∪Cnew的日志后更新本地日志,并且马上就以该配置作为自己的成员配置;

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

2、提交Cnew

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

Follower收到新成员配置Cnew后,将其写入日志,并且马上就以该配置作为自己的成员配置,并且如果发现自己不在Cnew这个成员配置中会自动退出。

可以看到,Raft算法将成员配置的变化也作为一条日志,需要经过一轮Raft过程像应用操作一样只要大多数节点确认了就肯定不会出出脑裂了。注意Follower收到配置后马上就变更,而不需要等Leader下次发送commitIndex的时候才提交,这点是和正常应用提交不一样的地方。

这里不去做详细的证明,官方有详细说明,我们可以看下几个异常,还是以上面的例子,当前集群有3个节点:1、2、3,现在要增加2个节点:4、5,假设当前Leader为1,具体过程如下:

1)节点1收到成员变更的请求,生成一条日志类型为成员变更,内容为:1、2、3、4、5,节点1将这条日志先保存到本地,但不马上更改成员配置;

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

3)2、3、4、5节点收到配置后做2件事:追加日志,马上变更自己的成员配置为:1、2、3、4、5;

4)节点1只要收到2个以上节点回复马上将自己成员配置为:1、2、3、4、5.

我们看有哪些异常:

如果有1-2过程中失败了,则整个过程就算失败,则需要管理员重新发起成员变更操作;

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

如果在第4步节点1挂了的话,新集群肯定是有这个配置的,因为根据日志最新原则,新选举出来的Leader肯定包含上面成员变更的日志。

三、其它问题

1、新加的成员入无日志

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

2、移除不在 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掉。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员升级之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档