引言
成员变更问题也是Raft非常重要的一部分,但却有些不好理解,在论文中第一次看到的时候确实是有些不知所云的,但是机缘巧合的情况又看到了另一种方法,遂回头又整理了一下思路,所以专门记录一篇文章,以帮助其他有相同疑问的朋友.
问题描述
Raft算法我们一直都假设节点数目是不变的,就算节点减少其实问题也不是很大,因为算法的安全性并未被破坏,但是当出现节点增加的时候就不一样了,可能因为出现网络分区的情况而出现脑裂(两个leader),假设现在有三个节点A,B,C,A为leader,新加入两个节点,此时出现网络分区.即出现脑裂,如下:
因为现在在节点A眼中还认为集群有三个节点,而C却知道有五个节点,但是此时出现两个"大多数"集合,所以出现脑裂.这也是因为各个服务器提交成员变更日志的时刻可能不同,造成各个服务器从旧成员配置(Cold)切换到新成员配置(Cnew)的时刻不同,也就是它们的集合没有交集,上图的配置转换状态如下:
上图来自Raft算法论文的图片10,它描述了第一幅图每个节点的配置状态(Server1为A,以此类推),即A,B节点还是Cold,但是B,C,D确拥有最新的配置,即Cnew,也就是我们所说的网络分区.
此时违背“领导者的唯一性”原则,这样就会影响到集群的稳定运行,这个问题最简单的解决方案就是集群服务下线,然后更新配置,随后上线,但是这样的做法显然违反了高可用的原则,毕竟流量为王的时代,分分钟几百万上下啦(手动狗头).对于这个问题有两种解决方式,即一阶段成员变更
和二阶段成员变更
二阶段成员变更
这也是Raft作者Diego Ongaro在论文中给出的解决方案,它允许以此向集群中插入多个节点而不会出现安全性问题,此外,还可以让集群在配置转换的过程依然响应服务器请求.集群配置在复制日志中以特殊的日志条目来存储和通信,当一个请求加入节点的信息传递给leader的时候把配置状态改为C-old-new这样一个特殊状态,一旦这个特殊状态(C-old-new)已经被提交了,那么系统就切换到新的配置(Cnew)上,这个状态有以下特点:
- 日志条目被复制给集群中新,老配置的所有服务器.
- 新,旧配置的服务器都可以成为领导人(当然选举取决于日志版本).
- 达成一致(针对选举和提交)需要分别在Cold和Cnew上获得大多数的支持.
特殊的,如果领导人崩溃了,被选出来的新领导人可能是使用 C-old 配置也可能是 C-old-new 配置,这取决于赢得选举的候选人是否已经接收到了 C-old-new 配置,在任何情况下,C-new 配置在这一时期都不会单方面的做出决定(因为选举选取的是日志最全的一个节点,如果leader没有发送一个 C-old-new日志条目的话,leader日志为Cold,如果发送了至少一个的话,leader日志为C-old-new).这样就算出现分区也不会出现脑裂了.因为此时不会出现在第一幅图那样原节点拥有Cnew(C-old-new)还当选成功了,也即是不会出现Cold和Cnew不相交的情况.
简单分析一下:
- leader没有发送任何一个C-old-new日志就宕机,此时只有Cold会当选leader,使用第一幅图来做说明,此时C不知道D,E存在,不会出现脑裂.
- leader已经发送了C-old-new日志后宕机,此时cold和cnew都可能当选,但是出现图一分区后因为第三条约束A节点(C-old-new)也不会当选为leader.
以上是leader在C-old-new状态时的情况,而如果这个时候不会出现问题,那么全局统一状态的时候也不会出现问题了.整体的状态转移如下:
一个配置切换的时间线。虚线表示已经被创建但是还没有被提交的条目,实线表示最后被提交的日志条目。领导人首先创建了 C-old,new 的配置条目在自己的日志中,并提交到 C-old,new 中(C-old,new 的大多数和 C-new 的大多数)。然后他创建 C-new 条目并提交到 C-new 中的大多数。这样就不存在 C-new 和 C-old 可以同时做出决定的时间点.
因为二阶段成员变更实现难度过大,目前主流的Raft算法很少采用二阶段成员变更.
一阶段成员变更
这个就比较简单了,因为一次向集群中加入节点不会出现Cnew,Cold两个集合不相交的情况.举个例子:
这就意味着出现新节点的那个分区选举不会成功.当然这个算法也意味着一次成员变更成功前不允许开始下一次成员变更.
总结
解决问题的过程是有意思的,但是也愈加感到力不从心,有时实在是脑力欠佳,还是需要搞清楚自己的定位,走好每一步即可.
参考:
- 博文 《Raft算法之成员变更》
- 课程 《韩健 分布式协议与算法实战》
- 论文 《In Search of an Understandable Consensus Algorithm(Extended Version)》