分布式系统一致性解决方案——Paxos算法

  1. Paxos算法的出现

    分布式系统一般都要求高可用性,而高可用性一般又通过冗余也就是多副本来解决,所以多副本的引入又会带来了副本的数据一致性问题,所以分布式系统要解决的问题可简单归结为多副本的一致性问题。而Paxos算法的出现正是为了解决此类问题。

  2. Paxos算法概述

    网上的资料众多,这里进行高度概述,如下:
    1.Paxos 算法是一种基于消息传递模型的一致性算法
    在分布式系统中,节点之间通过共享内存和消息传递来进行信息交换。而在消息传递中,可能会遇到网络问题或者节点问题,这会造成消息不可达或者消息重复的现象。Paxos算法正是帮助我们解决这种现象的一致性算法。
    2.Paxos 算法解决的问题是一个分布式系统如何就某个值(决议)达成一致
    这个是Paxos算法的典型应用场景。比如在一个分布式系统中,如何选出一个协调者,由它来协调整个集群的正常工作,这个选择的过程可以看做一次Paxos算法的计算过程,Paxos算法计算的结果值可以看做是选出的协调者的机器ID。
    3.Paxos 算法的前提是不存在拜占庭将军问题
    拜占庭将军问题是一个协议问题,拜占庭帝国军队的将军们必须全体一致的决定是否攻击某一支敌军。问题是这些将军在地理上是分隔开来的,并且将军中存在叛徒。叛徒可以任意行动以达到以下目标:促成一个不是所有将军都同意的决定,如当将军们不希望进攻时促成进攻行动;或者迷惑某些将军,使他们无法做出决定。如果叛徒达到了这些目的之一,则任何攻击行动的结果都是注定要失败的,只有完全达成一致的努力才能获得胜利。Paxos算法的前提是有一个可信的通信环境,即消息准确,没有被篡改。

  3. Paxos算法的主要内容

    proposer:提出议案者,提出议案的角色。
    acceptor:议案判断者,收到议案后进行判断的角色,可以批准或者拒绝议案
    proposal:议案,一个议案由{编号,决议}组成。
    主要分为两阶段:prepare阶段,accept阶段。
    一.prepare阶段
    1.proposer会发送一个proposal{n,v}给一个acceptor的多数派。
    2.acceptor按照以下规则进行议案判断:
    <1>如果acceptor第一次收到议案,则它会批准议案。
    <2>如果acceptor不是第一次收到议案,而且它发现n是它已回复的proposal中编号最大的,那么它会回复它已经accept的最大proposal{n1,v1},同时附带承诺:不会批准编号小于n的proposal。
    <3>如果acceptor不是第一次收到议案,而且n小于它已回复的proposal中编号最大的,那么它会拒绝议案并回复“它已回复的proposal中最大的编号”。
    3.如果proposer接收到了多数派的回应,那么会进入accept阶段。
    二.accept阶段
    1.如果proposer接收到了多数派的回应,它发送一个accept消息{n,v}到acceptor的多数派(可以与prepare阶段的多数派不同),这个accept消息中的v的取值规则为:如果acceptor在prepare阶段中的回应包含了v,则取其编号最大的那个作为v;如果回应中不包含任何v,则由proposer随意选择一个。
    2.acceptor接收到accept消息后检查,如果没有比n大的proposal,则accept对应的v;否则拒绝或不回应。

  4. Paxos算法的具体实例

    假如系统中有N个acceptor,则多数派个数至少为N/2+1。如果多个proposer在prepare阶段接收到了多数派的回应,那么这些多数派集合中至少有一个acceptor是相同的。举例来说,就是如果有两个proposer,记为proposerA与proposerB,它们两个在prepare阶段接收到了多数派的回应,proposerA的多数派集合为a,proposerB的多数派集合为b,那么存在acceptorC,既属于a集合又属于b集合。
    现在的例子是,系统中有2个proposer,5个acceptor,它们通过Paxos算法确定一个值value的过程如下(假设n1 < n2)。
    首先在prepare阶段,proposerA选择它的多数派为acceptorA,acceptorB,acceptorC,proposerB选择它的多数派为acceptorC,acceptorD,acceptorE。对于proposerA,proposerA会发送proposal{n1,v1}给它的多数派,由于acceptor都是第一次参与议案,所以它们会直接批准议案。

    对于proposerB,proposerB会发送proposal{n2,v2}给它的多数派,此时acceptorD,acceptorE都是第一次参与议案,所以它们会直接批准议案。但是acceptorC在之前已经批准了proposerA的议案,所以acceptorC根据Paxos算法,会批准proposerB的proposal。

    对于proposerA与proposerB,它们都接收到了多数派的回应,所以都会进入accept阶段。对于proposerA,它发送一个accept消息{n1,v1}到多数派(假设选择的多数派与prepare阶段相同),此时对于acceptorA,acceptorB,它们会accept该proposal,但是对于acceptorC,它在检查中发现存在一个编号为n2的proposal,由于n2 > n1,所以acceptorC会拒绝该proposal。所以proposerA的accept阶段失败。

    对于proposerB,它发送一个accept消息{n2,v2}到多数派(假设选择的多数派与prepare阶段相同),此时对于acceptorC,acceptorD,acceptorE它们都会accept该proposal。所以此时acceptorC,acceptorD,acceptorE中已经确认的值为v2。

    对于proposerA,它在失败后会把n1增加,然后重新进入prepare阶段(此时n1 > n2。因为失败后对于proposer来说需要增大编号来继续进行算法)。在prepare阶段中acceptorC会回复它已经accept的最大proposal{n2,v2}。此时proposerA获得了v2。在accept阶段,会把v2作为它的取值向它的多数派发送申请,最终acceptorA,acceptorB,acceptorC中已经确认的值也为v2,最终v2为最终的取值,他们达成了一致。

  5. Paxos算法存在的活锁问题

    描述:如果系统中有多个proposer同时提proposal,可能会出现编号冲突,然后双方都会增加proposal的编号继续提交,然后又冲突,就会造成死锁。
    解决:在整个集群中设置一个leader,所有的proposal由它来提,这样可以避免冲突,也就是解决活锁的问题。但是这样又会有单点问题。
    再改进:当leader挂掉后,重新进入leader选举。

  6. 总结

    首先,明确Paxos算法所要解决的问题,在一个可能发生异常的分布式系统中如何就某个值达成一致,让整个集群的节点对某个值的变更达成一致。
    其次,明确Paxos算法的核心思想,少数服从多数,每次做决定都要获得一个多数派的批准。
    最后,Paxos算法也存在一些问题,比如活锁问题,具体解决可以是设置leader,然后通过leader选举来解决单点问题。

发布了19 篇原创文章 · 获赞 20 · 访问量 5860

猜你喜欢

转载自blog.csdn.net/qq_15898739/article/details/84073096