将成员变更纳入到算法中是Raft易于应用到实践中的关键,相对于Paxos,它给出了明确的变更过程(实践的基础,任何现实的系统中都会遇到因为硬件故障等原因引起的节点变更的操作)。

显然,我们可以通过shutdown集群,然后变更配置后重启集群的方式达到成员变更的目的。但是这种操作会损失系统的可用性,同时会带来操作失误引起的风险。支持自动化配置,即配置可以在集群运行期间进行动态的变更(不影响可用性)显示是一个非常重要的特性。

Raft成员变更机制

在成员变更时,因为无法做到在同一个时刻使所有的节点从旧配置转换到新配置,那么直接从就配置向新配置切换就可能存在一个节点同时满足新旧配置的“超过半数”原则。

如下图,原集群由Server1、Server2、Server3,现在对集群做变更,增加Server4、Server5。如果采用直接从旧配置到新配置的切换,那么有一段时间存在两个不想交的“超过半数的集群”。

上图,中在中间位置Server1可以通过自身和Server2的选票成为Leader(满足旧配置下收到大多数选票的原则);Server3可以通过自身和Server4、Server5的选票成为Leader(满足新配置线,即集群有5个节点的情况下的收到大多数选票的原则);此时整个集群可能在同一任期中出现了两个Leader,这和协议是违背的。

为了保证安全性,Raft采用了一种两阶段的方式。

第一阶段称为joint consensus,当joint consensus被提交后切换到新的配置下。

joint consensus状态下:

  • 日志被提交给新老配置下所有的节点
  • 新旧配置中所有机器都可能称为Leader
  • 达成一致(选举和提交)要在两种配置上获得超过半数的支持

具体的切换过程如下:

  • Leader收到C-old到C-new的配置变更请求时,创建C-old-new的日志并开始复制给其他节点(和普通日志复制没有区别)
  • Follower以最新的配置做决定(收到C-old-new后就以C-old-new来决定),Leader需要以已经提交的配置来做决定(即只有C-old-new复制到大多数节点后Leader才以这个配置做决定);这个时候处于一个共同决定的过程
  • 之后提交C-new到所有节点,一旦C-new被提交,旧的配置就无所谓了

从上图可以看出,不存在一个阶段C-old和C-new可以同时根据自己的配置做出决定,所以不会出现本文开头描述的情况。

Review成员变更

如果当前的Leader不在C-new的配置中会怎么样(即当前的Leader是一个要被下线的节点)?

在C-old-new的状态下,Leader依旧可用;在C-new被commit之后Leader实际已经从集群中脱离,此时可以对Leader节点进行下线操作,而新集群则会在C-new的配置下重新选举出一个Leader。

如果在配置分发过程中Leader Crash了会怎么样?

这个问题要分为多种情况:1. C-new已经分发到超过半数节点、2. C-new还没分发到超过半数的节点

情况1:C-new已经分发到超过半数节点

集群开始重新选举,此时在C-new的规则下,旧节点(不存在新配置中的节点)不会赢得选举(因为他们要在C-old-new的情况下决定,但是拿不到C-new的选票),只有拿到C-new的节点可能成为Leader并继续下发C-new配置,流程恢复。

情况2:C-new还没分发到超过半数的节点

这种情况下,C-old-new和C-new的节点都可以成为Leader,但是无所谓,因为无论谁成为Leader,都能根据当前的配置继续完成后续流程(如果是C-new那么相当与完成了最终的配置,不在C-new的节点会因为没有心跳数据而失效)

旧节点下线造成的问题:旧节点收不到心跳触发选举,发送请求给C-old-new中的节点,是否会影响集群正常运行

Raft的处理方式:当节点确信有Leader存在时,不会进行投票(在Leader超时之前收到新的投票请求时不会提升term和投票)。且开始选举之前等待一个选举超时时间,这样在新Leader正常工作的情况下,不会受到旧节点的影响。

旧节点在发起选举前需要等待一段时间,那么这段时间新Leader可以发送心跳,这样就减少了影响。 对正常流程的影响不大。(Leader失效后要等一段时间,没有及时触发,然而本身这里就有一个判断失效的时间,好像影响不大;比如原先超时时间是10s,那么如果设置成5s,原策略下10s超时就是10s后开始选举,新策略下5s超时就是超时后再等5s再开始选举,影响就是超时时间变短)

新的服务器没有任何数据,加入进来进来怎么保证系统的可用性(这个时候新日志没办法Commit就没办法响应给客户端)?

新加入的节点需要时间复制数据,在这个过程完成之前,Raft采用以下机制来保证可用性: 新加入节点没有投票权(Leader复制日志给他们,但是不将他们考虑在机器数量里面——即在判断是否超过半数时不把这些节点考虑在内),直到这些节点的日志追上其他节点。

参考资料

论文:https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf

翻译:https://github.com/maemual/raft-zh_cn

动画演示:http://thesecretlivesofdata.com/raft/

解读Raft(四 成员变更)的更多相关文章

  1. etcd raft如何实现成员变更

    成员变更在一致性协议里稍复杂一些,由于不同的成员不可能在同一时刻从旧成员组切换至新成员组,所以可能出现两个不相交的majority,从而导致同一个term出现两个leader,进而导致同一个index ...

  2. 解读Raft(一 算法基础)

    最近工作中讨论到了Raft协议相关的一些问题,正好之前读过多次Raft协议的那paper,所以趁着讨论做一次总结整理. 我会将Raft协议拆成四个部分去总结: 算法基础 选举和日志复制 安全性 节点变 ...

  3. 【翻译】Raft 共识算法:集群成员变更

    转载请注明出处:https://www.cnblogs.com/morningli/p/16770129.html 之前都在集群配置是固定的(参与共识算法的server集合)假设下讨论raft.在实践 ...

  4. AFNetworking 3.0 源码解读(四)之 AFURLResponseSerialization

    本篇是AFNetworking 3.0 源码解读的第四篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3 ...

  5. Redis开源项目的终极杀手? ——CRUG解读Redis开源协议变更

    引言: 数据库制造商 Redis Labs 本周将公司开发的Redis 模块从 AGPL 迁移到将 Apache v2.0 与 Commons Clause 相结合的许可证,对许可证涵盖的软件作了限制 ...

  6. Alamofire源码解读系列(四)之参数编码(ParameterEncoding)

    本篇讲解参数编码的内容 前言 我们在开发中发的每一个请求都是通过URLRequest来进行封装的,可以通过一个URL生成URLRequest.那么如果我有一个参数字典,这个参数字典又是如何从客户端传递 ...

  7. 解读TCP 四种定时器

    TCP 是提供可靠的传输层,它使用的方法之一就是确认从另一端收到的数据.但是数据和确认都可能会丢失.TCP 通过在发送时设置一个定时器来解决这个问题.如果当定时器溢出时还没收到确认,它就会重传该数据. ...

  8. 解读Raft(二 选举和日志复制)

    Leader election Raft采用心跳机制来触发Leader选举.Leader周期性的发送心跳(如果有正常的RPC的请求情况下可以不发心跳)包保持自己Leader的角色(避免集群中其他节点认 ...

  9. 解读Raft(三 安全性)

    前言 之前的两篇文章更多的是在描述Raft算法的正常流程,没有过多的去讨论异常场景. 而实际在分布式系统中,我们更多的都是在应对网络不可用.机器故障等异常场景,所以本篇来讨论一下Raft协议的安全性, ...

随机推荐

  1. Cocos2D中Action的进阶使用技巧(一)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...

  2. Dynamics CRM 2013 Homepage Ribbon 按钮引用多个Javascript资源

    在CRM的开发中ribbon的开发是比较重要的一环,很多客制化的功能都需要动用ribbon区,CRM2013中的名字已经改叫command bar了,但从老版本过来的人都还是习惯叫他ribbon. R ...

  3. 程序员高效Windows环境配置

            个人比较追求高效.效率.以下是我常用的windows配置希望对大家有帮助.(身为程序员,我特别喜欢mac pro的retina屏,在那编程简直是一种享受.等我买了mac pro在发一篇 ...

  4. Java项目源码为什么要做代码混淆(解释的很好)

    代码混淆,是将计算机程序的代码转换成一种功能上等价,但是难于阅读和理解的形式的行为.代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码.执行代码混淆的程序被称作代码混淆器.目前已经存在许多种 ...

  5. UNIX环境高级编程——进程关系

    一.终端的概念 在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(Controlling Terminal),控制终端是保存在PCB中的信息,而我们 ...

  6. 1013. Battle Over Cities (25)

    题目如下: It is vitally important to have all the cities connected by highways in a war. If a city is oc ...

  7. STL:list用法详解

    list容器介绍 相对于vector容器的连续线性空间,list是一个双向链表,它有一个重要性质:插入操作和删除操作都不会造成原有的list迭代器失效,每次插入或删除一个元素就配置或释放一个元素空间. ...

  8. Java实现简易的文件的迁移器

    Java作为世界上最受欢迎的一门编程语言,自然是有原因的.比如说我们可以直接的方便的调用其中的函数来实现我们想要的功能. 一个偶然的机会,我浏览API文档时发现了一个名为FileDialog的类,然后 ...

  9. 视音频编解码学习工程:AAC格式分析器

    =====================================================视音频编解码学习工程系列文章列表: 视音频编解码学习工程:H.264分析器 视音频编解码学习工 ...

  10. 小强的HTML5移动开发之路(1)——HTML介绍

    来自:http://blog.csdn.net/dawanganban/article/details/17591373 HTML是HyperText Markup Language(超文本标记语言) ...