解读Raft算法二:Raft集群成员变更管理

1 集群成员变更的背景

Raft集群在运行过程中会遇到需要改变集群成员的情况,比如集群扩容、宕机节点替换等、控制复制进程等。Raft算法可以自动实现这一过程。

集群过程中面临的最大问题是脑裂问题,即在一个任期内出现了两个Leader的情况,这种情况是无法被允许的。因此扩展的首要问题便是如何在扩容过程中产生两个Leader。

2 集群成员变更的实现

2.1 单节点成员变更

  • 向Leader提交一个成员变更请求,请求的内容为服务节点的是添加还是移除,以及服务节点的地址信息
  • Leader在收到请求以后,回向日志中追加一条ConfChange的日志,其中包含了Cnew,后续这些日志会随着AppendEntries的RPC同步所有的Follower节点中
  • ConfChange的日志被添加到日志中是立即生效(注意:不是等到提交以后才生效)
  • ConfChange的日志被复制到Cnew的Majority服务器上时,那么就可以对日志进行提交了

Raft的作者Diego在博士论文中提到的g该单节点成员变更方法中有隐藏问题,可能会导致集群中的脑裂现象,具体的解决方法为必须等待变更配置日志必须要在提交后才能生效,在链接中给出了Diego对可能出现的脑裂现象的分析
https://groups.google.com/forum/#!topic/raft-dev/t4xj6dJTP6E

2.2 多节点成员变更

为了避免Raft中多节点成员变更中,采用了两阶段变更的策略:

  • 第一阶段:Leader发起Cold,new RPC,使整个集群进入到一种联合一致状态(joint consensus)。这时,所有RPC必须在新、旧配置的集群中达到大多数才能生效
  • 第二阶段:Leader发起Cnew RPC,使整个集群进入新配置状态。这时所有RPC之需要在新配置中达到大多数即可

配置变更的重要前提条件:一旦某个配置变更日志加入到节点的Log队列中,那么该节点未来的所有决策都基于最新的配置日志,而不管当前配置变更日志是否被提交。这一点与单节点成员变更不同。这也意味着Leader节点不需要等待Follower节点返回配置变更日志复制结果便可以基于新配置进行决策。此外关于集群变更日志还有限制:

  • 已复制了Cnew的节点,不可能在Leader选举时给没有Cnew的节点投票
  • 即使未提交的Cold,new 日志被Cnew提交日志覆盖,在提交Cold,new 日志时,依然需要判断其是否复制到了新、旧集群的大多数节点

集群变更的三个重要补充规则:

  • 新增节点时,必须等待新增节点完成日志同步后才能开始集群变更
  • 缩减节点的情况下,如果Leader本身就是被缩减节点,那么它会在完成Cnew日志的提交后自动退位(Leader在提交Cnew日志时不计入自己的票数)
  • 为了避免下线的节点没意识到自己被排除在集群外而发出RequesVoteRPC影响集群运行,节点会在确认集群中有Leader存在时拒绝该投票请求
posted @ 2024-03-21 00:02  sunjinxu  阅读(179)  评论(0)    收藏  举报