最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • 分布式系统选主怎么玩

    分布式系统为了保证其可靠性,一般都会多节点提供服务,各别节点的故障不会影响系统的可用性。对于分布式的存储系统来说,在保证可用性的同时,数据的可靠性(不丢失)也是其要解决的核心问题。目前通用的方案是使用多副本存储。这就会引入一个新的问题,分布式存储系统的又一核心问题——多个副本间的数据一致性保障。所以就有了各种数据一致性协议。例如:Zookeeper的Zab、Etcd使用的Raft和无比复杂的Paxos等等。这些一致性协议都有一个共同的特点,那就是都有一个主节点(Leader)负责数据的同步。

     

    本文不讨论这些一致性协议的工作原理,我们重点聊一聊它们的选主策略——当Leader挂掉后,集群必须有能力选出一个新的Leader。为什么只讨论选主呢?因为在我们的工作中几乎不太可能去设计实现一致性协议,但”选主”这个事儿还是有可能需要我们去做的。例如之前文章介绍的时间轮,我们有多个节点提供服务,但只能有一个节点去转动轮子(一秒移动一次当前指针),这个时候就需要系统中始终有一个Leader负责转动轮子。业务上类似的需求还有很多,这里就不举例了,接下来我们介绍下几种选主策略。

     

    首先明确下选主的时机:一般发生在集群的Leader宕机或者集群刚刚启动时,集群中没有Leader,这时就会触发选主。这里有两个技术点:

    1、集群中节点需要能够感知到Leader的存在;

    2、从剩余的活跃节点中选出一个新的Leader;

    选主常用的方式有两种:投票和竞争,下面我们分别介绍下。

     

    1. 投票选主

    在投票选主方式中,一般集群中会有两种角色:Leader和Follower,Leader和各Follower间保持心跳,Follower通过心跳判断Leader是否存活,如果Follower感知不到Leader,则触发选举。获得集群半数以上节点投票的Follower将成为集群新的Leader。为了提高选举的效率,集群节点数一般都为奇数个。

    那么Leader是如何选出来的呢?不同的一致性协议,有不同的玩法,下面简单了解下Zookeeper和Etcd的选主方式(为了便于理解对模型做了简化,只描述核心算法和思路):

       

    ZooKeeper

    ZK的节点在投票时是通过比较两个“ID”来决定把票投给谁的:

    1、ZXID:ZooKeeper事务Id,越大表示数据越新;

    2、SID:集群中每个节点的唯一编号;

    投票时的比较算法为:谁的ZXID大谁胜出,ZXID相同情况谁的SID大谁胜出(简单理解:谁的数据新胜出,数据一样谁的编号大谁胜出)。

    选举算法如下:

    1、集群失去Leader后,所有节点进入Looking状态,向集群中广播(第一轮投票)自身选举值(SID,ZXID),投自己一票;

    2、每个节点都会将自身选举值与收到的所有其它节点的选举值作比较,选出“最大”的,如果最大的不是自己,则改投最”大“节点,广播变更(第二轮投票);

    3、集群中节点收到第二轮结果后,统计超过半数的选举值,其对应的节点将成为集群新的Leader;选举过程入下图所示:

                   

    图1 ZooKeeper选主过程

       

    Etcd

    Etcd使用Raft一致性协议,集群中每个节点都有自己的倒计时器,且时间随机。Follower每次收到心跳后都会重置倒计时器,当某个Follower的倒计时结束,说明长时间没有收到心跳,就可以认为Leader挂了,需要选举新的Leader了。这个Follower就会触发选举,想成集群为新的Leader。

    Follower首先会将自身状态改为Candidate,并向所有节点发起投票,如果得到半数以上节点的同意则成为集群新的Leader。否则,在下次倒计时结束后发起新一轮选举。

    Raft选举过程中,投票节点通过对比任期(Term,一个连续递增的整型值)和CommitId(类似ZK的事务Id)来判断是否投“同意”票。选举过程如下:

    1、Candidate发起投票时将自身当前任期加1(NewTerm),并向集群中所有节点发起投票请求(请求中包含新的任期值);

    2、Follower节点将自身当前任期(CurrentTerm)和收到的Candidate投票请求中带来的NewTerm比较,如果NewTerm大就投“同意”票(这里忽略的CommitId的比较是为了更好理解和强调Term的作用,比较方法与ZK类似);

    3、Candidate得到大于半数节点的”同意“后成为Leader,与其他节点建立心跳,并更新所有节点的当前任期为NewTerm;

    4、如果不够半数,则选举失败,等待倒计时器下次到期发起下一轮选举;

    选举过程如图2、图3所示:

                 

    图2 Leader心跳中断,进入下一任期

     

    集群正常情况下,各节点处于同一任期,Leader节点定时发送心跳重置各Follower倒计时器,当Leader心跳中断后,Follower倒计时器不再被重置,则会必然会有节点到期,触发选举,图2中Follower 1先到期,变为Candidate并发起选举,进入下一任期。

                 

    图3 完成选举

    选举成功,原Follower成为集群新的主节点,开始向各Follower发送心跳,并更新其它节点的任期。

     

    上面介绍的流程只是最简单的场景,实际情况会复杂些,例如有可能会有产生多个Candidate,因为只要有Follower节点到期,就会发起投票,进入Candidate状态,Reft是如何尽量避免产生多个Candidate的呢?

    首先各节点倒计时时间随机,尽量避免同时到期。其次Follower收到Candidate的投票请求时会重置自己的倒计时器,这样就尽量保证了在选举失败后Candidate能够率先到期,可以下一任期继续由它发起投票。

    但是肯定还存在产生多个Candidate的情况,所以协议规定一个Follower在一个任期只能投一次票,这样就够不可能有两个Candidate同时获得半数以上的投票(不可能选出两个Leader来)。如果选举失败,由于节点倒计时器时间随机,所以几乎可以肯定会有一个Candidate先到期,并且大概率在下一轮选举中成为Leader。

    2. 竞争选主

    上面介绍的投票选举方式需要集群各节点互相感知对方的存在,实现相对复杂,下面介绍一种比较简单的方案——竞争选主。

    竞争选主需要借助外部存储服务来实现,各节点通过对某个约定的Key-Value数据的访问,来决定谁是Leader,假设KV数据为Leader:UUID(写入前生成的唯一Id),具体”抢主“逻辑如下:

    1、尝试获取Leader:UUID数据,判断数据是否存在;

    2、如果Leader不存在,则将Leader:UUID写入到存储服务中并设置其TTL(如果存储服务不支持TTL,可以将TTL作为Value的一部分一起写入),本地保存UUID值,当前进程为主节点;

    3、如果Leader存在,通过TTL判断是否过期,如果过期,当做Leader不存在处理,否则对比Leader的UUID和本地存储的UUID是否一致;

    3.1、如果一致则刷新”数据“TTL,当前进程为Leader;

    3.2、如果不一致则不作任何操作,当前节点不是Leader;

    集群内所有的进程,都保证以小于TTL的周期执行上述逻辑,Leader就会不停的“刷新”Leader:UUID的TTL,始终保持自己是Leader,如果想更安全,刷新时可以使用CAS的方式每次更新UUID。当Leader宕机不能继续刷新后,数据必然会过期,其它节点将会竞争写入,成为集群新的Leader(和分布式锁很像,可以理解为一把长期持有的锁,新的玩法)。

                 

    图4 竞争Leader

    我们分析下上述逻辑,当约定的Key不存在时,集群处于没有主或主挂了的状态,其他节点可以通过判断这个Key感知到Leader是否存在,从而触发选主,写入Key的过程相当于竞争选主的过程,谁写入成功谁就是新的Leader。

    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » 分布式系统选主怎么玩

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 176会员总数(位)
    • 3737资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 542稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级