Raft学习笔记【四】——安全性和增加集群

前言

Raft追求的是易于理解,所以有许多可以优化的地方,但是因为其应用场景并不多,所以为了易理解性大多采取了从简的做法,但是会提一嘴提供一种优化思路。当学习者学会了raft之后,再自己去优化这部分的内容,这种学习方式相比于一开始就把所有的细节问题讲清楚来说更加利于学习者理解。

我不得不感慨,国外这些大牛是真正的学者,他们没有一个高级知识分子的傲慢(?),他们理解每一个初学者的学习困难,因此他们会为了易理解性放弃一些性能,甚至放弃一些严谨性,因为他们知道,只有当初学者学会了之后,入门了以后,自然会去考虑性能优化和严谨性的探索,这些性能和严谨性不是他们想不到,而是他们有真正地站在一个初学者的角度去考虑。而大部分国内大学的教科书,是不会考虑初学者这部分的困难的,他们大都非常“傲慢”地把一个新知识体系完完整整地摆在初学者面前,理所当然地认为“你们学不会是你们不行”。所有这也造就了大学里非常多的书籍,完全是站在读者已经学会了的角度给读者每一个知识点的罗列,这更像一种工具书,而不是教科书。所以我说,国内的学者有一种高级知识分子的“傲慢”。这也是为什么,国外的名校,有m6.824,有15445这些优秀的课程,而我们的高校缺乏这些东西,甚至辅导员会卡本科生实习,导师会卡自己研究生工作,甚至出现过失使自己的研究生全部患癌这种匪夷所思的负面新闻。


安全性

有一些公式算法为了提高效率,允许非leader节点按乱序接收日志请求RPC。这导致了这些节点内部可能出现日志空洞,这些算法提供了非常复杂的机制来处理这些节点内部的空洞来达成一致性。而raft算法在设计之初就有一个非常清晰的目标——“易理解性”。所以raft只允许节点按顺序接收AppendEntryRequest RPC,这避免了复杂的边界情况处理。

即使如此,现有机制下,raft还是会有一些比较复杂的边界情况。这部分内容比较复杂,我不一定保证能讲清楚。所以如果以下内容理解起来有困难,我推荐去B站看一个up主的视频,讲的非常好,链接放在这里:

解读共识算法Raft(4)安全性_哔哩哔哩_bilibili

我们假设这样一种情况

S1-S5分别为5个节点,方框内的数字为日志号。

  1. 最开始的时候S1-S5都有1号日志,(a)阶段S1是leader,它已经把日志2发给了S2,这时候它发生了宕机
  2. 因为没有超过半数节点commit,所以该节点没有apply到状态机
  3. (b)阶段经过选举S5成为leader,接收了日志3,还没有分发发生了宕机
  4. (c)阶段S1重新当选leader,S1把日志2更新到了S3,这时S2完成了半数以上commit,S1将其apply,apply之后发生宕机
  5. (d)阶段S5重新当选leader,这时它继续Append日志3,而S2,S3因为日志号1之后是日志2,比日志3要“老”,所以被强制覆盖,导致了已经apply的数据被覆盖

针对这种边界情况,raft在请求投票RPC中会存储上一个日志的索引和上一个日志的任期。并规定——新leader会将老leader宕机时未能分发的日志进行复杂(给其他节点),但不会提交(commit)。

那这些被复制的日志怎么提交呢?只有当新leader收到新的日志,比如在(c)阶段之后的日志4分发且半数以上的节点commit后,leader就会在apply日志4的时候把老leader留下的日志2一并apply。这是因为日志4apply之后,就将日志2保护了起来,就不会出现图中阶段(d)那种其他leader将日志2覆盖的情况。


心跳RPC和时间限制

前面几章我们只讲了在leader收到半数以上的commit回复之后就会把日志apply到状态机,但是follower不会知道什么时候这个commit什么时候apply啊,这怎么办呢?哎,注意看第三章的追加日志RPC内的LeaderCommit参数,这个参数就记录了leader哪些日志是已经apply的。而当follower收到AppendEntriesRequest RPC后就可以根据该参数apply自己日志库中已经半数commit的日志。

那么,难道follower节点就只能在收到新的请求添加日志RPC之后才能apply上一次的日志吗?其实并不是,其实leader除了RequestVoteRPC和AppendEntryRequestRPC之外,还有心跳RPC。心跳RPC内没有body内容,只发送如LeaderCommit之类的设置参数,leader也正是靠心跳RPC告知集群内其他节点leader正常运行。

在整个集群系统中,有3个时间需要我们注意。一个是广播时间,即一个数据从leader发送到follwer,再从follwer发回leader时间;还有一个是系统平均宕机时间。这两个时间取决于硬件,比如网络通信速度和设备的质量,而选举超时时间是raft算法内部决定的,选举超时时间的选择规则是:

  1. 广播时间 << 选举超时时间 << 系统平均宕机时间
  2. 选举超时时间不能是一个固定的时间

以上两点保证了集群内的节点不会因为选举超时时间比广播时间小,导致永远选不出leader;以及选举超时时间比系统平均宕机时间大,导致永远选不出leader。而一般系统平均宕机时间往往是几个月不用考虑,广播时间一般在0.5ms-20ms之间(取决于存储技术),所以在raft论文中作者推荐的选举超时时间是10-500ms,具体落地时还要根据广播时间来决定,但不要超过广播时间两个数量级。这会导致系统效率降低。


联合一致方法集群节点变更

脑裂问题

在集群中有时会遇到需要添加节点或者删除节点的情景,面对这种情景,如果没有集群成员变更的方法,那么就需要手动地关闭分布式系统,再增加或删除节点。这导致了每当要更新集群节点时,系统就要暂停对外服务,这种方法既不高效,也可能因为人员手动配置的问题导致出错。所以raft自身设计了一种用于自动更新成员节点的方法。

自动更新集群节点遇到的最大的难点就是”脑裂问题“

所谓脑裂问题就是,在一个集群中, 新加入的节点和原本集群中的节点处于两个不同的系统,导致两边分别进行选举,进而出现一个集群内部出现两个leader的现象,这种现象就成为脑裂问题。

打个比方:

  1. 假如现在原集群中有3个节点,S1-S3,其中S3是当前节点的leader。
  2. 这时新加进来两个节点S4 S5,leader将他们划入集群的范围内,但是这个信息还没有同步给S1S2时,S3的任期结束了。也就是说S1 S2不知道集群内部的节点数量变成了5,于是S1S2在内部选出一个leader
  3. 而新进来的S4 S5也参与了选举,S3 S4 S5是知道集群内有5个节点的,但是他们一共有3票,也可以在内部选出一个leader

于是,出现了一个集群出现两个leader的情况。

解决方法

为了解决这种现象,raft设计了一个联合一致状态,作为老状态和新状态之间的一个状态。来解决上述可能出现的脑裂问题。所谓联合一致状态,是指leader给所有新加进来的leader分发新的状态配置——联合一致状态。前提是新加进来的节点已经跟上了日志的进度。

leader的节点会通过将该配置放在一个普通的AppendEntrieRequest RPC中分发给follower。当集群中的节点收到一个新的配置信息后,无论该信息是否commit 或apply,之后的所有决策都会按照该配置来决定。而联合一致状态配置中就明确要求了,节点需要同时满足新配置和老配置的投票条件才能当选leader。拿上面的例子举例的话就是:
 

  1. 假如现在S3将联合一致状态分发出去,而S1 S2未收到,S4 S5 收到了。
  2. 此时S3的任期到了,进行新一轮的选举的时候,S3 S4 S5不但要获得5个节点的半数以上选票,还需要获得S1 S2 S3三个老配置的半数以上的选票。
  3. 而S1 S2在未当选之前是不知道S4 S5的存在的,所以不会给他们投票,因此S3 S4 S5就不可能当选leader,所以新leader只能从S1 S2中间选,这种情况下集群变更请求失败,但是避免了脑裂问题

而当不止S3 S4 S5变成联合一致状态,S1 S2也变成联合一致状态时,就消除了S1 S2不知道S4 S5的信息差,自然不会选出两个leader。

在联合一致状态后,新leader会尽快给每个follower分发普通状态的配置,由于此时集群内部的信息差已经不会出现选出两个leader的情况,所以这个流程是安全的,集群就成功地自动完成了集群成员增加。

其实raft的作者在这部分的设计时还是低估了这部分变更的复杂性和边界条件,所以工程里的raft集群变更往往采用的是单节变更,复杂度会低很多。但这部分内容不在论文里,将由设计者来自行设计了。


结束语

碍于时间和个人能力限制,本篇我并未画较多的图,可能看起来有些乏味,建议感兴趣的同学可以继续看一些优秀的博客,他们花了大量的时间画了许多的状态图帮助理解,我这里仅仅是有助于自己理解。关于raft算法的学习就告一段落,后面如果有时间,可以写写谷歌阿里云的这些基于raft的实际工程的实现的文章,如果我没忘的话^ ^嘿嘿

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值