一致性协议—— Paxos算法

Paxos算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题 最有效的算法之一。在一致性协议——2PC及3PC中,我们提到过了2PC和3PC的一些缺点,比如单点故障、容错机制不完善等等,而Paxos算法运行在允许宕机故障的异步系统中,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复。它利用大多数 (Majority) 机制保证了2F+1的容错能力,即2F+1个节点的系统最多允许F个节点同时出现故障。


其Paxos的流程图如下,其中具体的流程步骤下面会详细介绍
在这里插入图片描述

Paxos将系统中的角色分为提议者 (Proposer),决策者 (Acceptor),和最终决策学习者 (Learner):

  • Proposer: 提出提案 (Proposal)。Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value)。
  • Acceptor: 参与决策,回应Proposers的提案。收到Proposal后可以接受提案,若Proposal获得多数Acceptors的接受,则称该Proposal被批准。
  • Learner: 不参与决策,从Proposers/Acceptors学习最新达成一致的提案 (Value)。

一个或多个提议进程(Proposer) 可以发起提案 (Proposal),Paxos算法使所有提案中的某一个提案,在所有进程中达成一致。系统中的多数派同时认可该提案(少数服从多数),即达成了一致。最多只针对一个确定的提案达成一致,大多数决策者 (Acceptor)接受了某个值后,该值才算被接受,即可以被决策者读到该值,这是Paxos算法的一个必须满足的约束条件。




那么我们首先来看一个极端的例子,每当任何一个提议进程 (Proposer) 发起了提案 (Proposal) ,所有的或者大多数的决策者 (Acceptor) 都不同意,那么该怎么办呢?是不是意味着永远没有办法达成一致呢?是的,为了避免这个问题,所以规定了一个决策者 (Acceptor) 必须需要接受其第一次收到的提案 (Proposal),即上图Paxos算法流程图中第一阶段,会先判断if(MaxN==null),回应(ok, null, null),其中返回null是指当前还没有接受/同意任务的提案 (Proposal),这个值后续还会详细介绍。
在这里插入图片描述


那么现在假设只有一个提议进程 (Proposer) 发起了提案 (Proposal) ,那流程就非常简单了,如下:
在这里插入图片描述




上述是我们假设的只有一个提议进程 (Proposer) 发起了提案 (Proposal) ,每个提案 (Proposal) 都有拥有一个提案编号N,那么现在如果有多个提议进程 (Proposer) 发起了提案 (Proposal) ,那么又会怎么样呢?这时我们就需要进行投票了,即我们需要使多数派同时认可同一个提案,其过程如下:


每个提议者 (Proposer) 选择一个提案 (Proposal) ,然后向决策者 (Acceptor) 集合发送请求,要求该所有决策者 (Acceptor) 中至少有半数以上同意提案 (Proposal) ,即决策者 (Acceptor) 同意一下几点:

  1. 不再接受提案 (Proposal) ID小于等于(注意:这里是 <= )当前请求的Prepare请求 ,即向提议者 (Proposer) 承诺保证不再接受任何编号小于N的提案,这里是指Paxos算法流程图中的第一阶段——准备阶段
  2. 如果决策者 (Acceptor) 已经接受过提案,那么就向提议者 (Proposer) 响应已经接受过的编号小于N的最大编号的提案
  3. 不再接受提案 (Proposal) ID小于(注意:这里是 < )当前请求的Propose请求 ,这里是指Paxos算法流程图中的第二阶段——同意阶段



1、不再接受提案 (Proposal) ID小于等于(注意:这里是 <= )当前请求的Prepare请求

首先我们现在看第一点,每个提案 (Proposal) ID都有一个编号,编号高的提议优先级高,为了保证不同的提议者 (Proposer) 提出的提案 (Proposal) 上面的编号不一样,需要特殊的机制来获取编号,编号必须包含节点信息以及节点本身提出的时序性(比如可以根据系统中的决策者 (Acceptor) 的数量n 以及这个提议者 (Proposer) 的编号m ,例如编号为m的提议者 (Proposer) 提出的提案 (Proposal) 的编号变化方式为m+i*n,i 是提出proposal的次数,即 i >=0
在这里插入图片描述




2、如果决策者 (Acceptor) 已经接受过提案,那么就向提议者 (Proposer) 响应已经接受过的编号小于N的最大编号的提案

然后我们再来看看第二点,这点主要发生在其中一个提议者 (Proposer) A 的提案 (Proposal) 在第一阶段——准备阶段通过了大多数的决策者 (Acceptor) 同意,所以决策者 (Acceptor) 已经接受过提案了,达成了一致意见,接受提议者 (Proposer) A 的提案 (Proposal) ,但是还没有经过最终的确定。提议者 (Proposer) A 肯定是进入了第二阶段,去找决策者 (Acceptor) 真正的落实确定该提案 (Proposal) 。一般情况如下:
在这里插入图片描述


但是就是这个时间点,决策者 (Acceptor) 们已经统一了意见,只是还没有最终确定,这时又来了新的提议者 (Proposer) B ,提出来新的提案 (Proposal) ,且条件更加的诱人(提案 (Proposal) ID较大),这时候决策者 (Acceptor) 就可以进行叛变了,转而同意提议者 (Proposer) B 的提案。


但是他们告诉提议者 (Proposer) B,我们虽然同意了你的提案,但是由于你来晚了,我们决策者 (Acceptor) 们已经统一了意见,在你之前我们已经同意了提议者 (Proposer) A 的提案,我们告诉你提议者 (Proposer) A 的提案具体内容,这里向提议者 (Proposer) B 透露提议者 (Proposer) A 的提案内容的原因,我们下面会具体介绍。
在这里插入图片描述




这里我们就来谈一谈提议者 (Proposer) B 透露提议者 (Proposer) A 的提案内容的原因,这里我们先来看看提议者 (Proposer) B 拿到提议者 (Proposer) A 的提案内容的用途,这里我们提议者 (Proposer) A 在第二阶段进展顺利,得到了大多数决策者 (Acceptor) 的确认,就就结束了。
在这里插入图片描述


但是如果提议者 (Proposer) B 在提议者 (Proposer) A 得到了大多数决策者 (Acceptor) 的确认之前,就策反了大部分的决策者 (Acceptor) ,这是提议者 (Proposer) A 由于得不到大多数决策者 (Acceptor) 的确认,所以只能回到第一阶段,再次重复发起之前的流程。
在这里插入图片描述


这里提议者 (Proposer) A 在第二阶段的失败回到第一阶段,但是如果提议者 (Proposer) B 获得大部分决策者 (Acceptor) 的统一,那就能够顺利进入的第二阶段,但是由于决策者 (Acceptor) 们在之前已经统一了意见,即同意了提议者 (Proposer) A 的提案,尽管提议者 (Proposer) A 在第二阶段失败了,但是决策者 (Acceptor) 们已经同意了这个提案的内容,所以提议者 (Proposer) B 在第二阶段发起提案 (Proposal) 确认的时候,就必须以之前提议者 (Proposer) A 的提案 (Proposal) 内容进行提交确认,即如果一个带有某个Value的提案 (Proposal) 被选中,那么所有的带有较高编号的提案 (Proposal) 中的值必须也是这个Value
在这里插入图片描述


这里是为什么会要求如果一个带有某个Value的提案 (Proposal) 被选中,那么所有的带有较高编号的提案 (Proposal) 中的值必须也是这个Value,这里我们假设,如果我们有5个决策者 (Acceptor) ,但是由于网络原因掉线了2个,现在只有3个决策者 (Acceptor),并且3个决策者 (Acceptor) 就同意提案 (Proposal) 达成了一致,这是网络好了,掉线的2个决策者 (Acceptor) 重新连接上了,这是如果这2个决策者 (Acceptor) 接收到了新的提案 (Proposal) ,根据之前的一个决策者 (Acceptor) 必须需要接受其第一次收到的提案 (Proposal) 原则,他们必须接受该新的提案 (Proposal) ,这里就到导致系统的不一致的现象,如果有上述限制,虽然介绍的不是同一个提案 (Proposal) ,但是其实提案 (Proposal) 的内容都是一致的,所以可以保证其一致性。




3、不再接受提案 (Proposal) ID小于(注意:这里是 < )当前请求的Propose请求

最后一点是什么意思呢?这点我们还是需要在第2点的基础上进行解释,主要针对的是Paxos算法流程图中的第二阶段——同意阶段,上述说到提议者 (Proposer) A 的提案 (Proposal) 在第一阶段——准备阶段通过了大多数的决策者 (Acceptor) 同意,这时它就进入了第二阶段,去找决策者 (Acceptor) 真正的落实该提案 (Proposal) 。
在这里插入图片描述


但是在这个时间点,正当该提议者 (Proposer) A 找决策者 (Acceptor) 真正确定提案 (Proposal) 的时候,这时又有一个新的提议者 (Proposer) B 正进行第一阶段,它正在找决策者 (Acceptor) 来同意自己的提案 (Proposal) ,这时如果提议者 (Proposer) B 的提案 (Proposal) ID 较大,那么决策者 (Acceptor) 就会叛变了,又会同意提议者 (Proposer) B 的提案 (Proposal) ,并透露提议者 (Proposer) A 的提案 (Proposal) 内容,这点在上述的第二点已经详细的介绍过了
在这里插入图片描述


这里如果提议者 (Proposer) A 在第二阶段已经找过该名叛变的决策者 (Acceptor) ,那么也没事,但是如果它晚了一步,在叛变之后再来找它,不好意思,该名叛变的决策者 (Acceptor) 改变主意了,之前的作废,现在就不理会提议者 (Proposer) A
在这里插入图片描述




上述就是整个Paxos算法流程图的详细介绍,总结一下其实就是分为两个阶段

  1. 第一阶段——准备阶段
    1. 提议者 (Proposer) 选择一个提案编号N,然后向半数以上的决策者 (Acceptor) 发送编号为N 的提案 (Proposal)
    2. 如果一个决策者 (Acceptor) 收到一个编号为N的提案 (Proposal) 请求,且N 大于该决策者 (Acceptor) 已经响应过的所有提案 (Proposal) 请求的编号ID,那么它就会将它已经接受过的编号最大的提案(如果有的话)作为响应反馈给Proposer,同时该决策者 (Acceptor) 承诺不再接受任何编号小于N的提案
  2. 第二阶段——同意阶段
    1. 如果提议者 (Proposer) 收到半数以上决策者 (Acceptor) 对其发出的编号为N 的提案 (Proposal) 请求的响应,那么它就会发送一个针对[N,V] 提案的Accept 请求给半数以上的决策者 (Acceptor) 。
      ( 注意: V 就是收到的响应中编号最大的提案的内容Value,如果响应中不包含任何提案,那么V 就由Proposer自己决定 )
    2. 如果决策者 (Acceptor) 收到一个针对编号为N 的提案的Accept 请求,只要该决策者 (Acceptor) 没有对编号大于N 的Prepare 请求做出过响应,它就接受该提案。



通过上述Paxos算法过程的了解,我们还发现一个问题,就是多个提议者 (Proposer) 可能会在第一阶段和第二阶段中陷入死循环,就是每当提议者 (Proposer) 能够进入第二阶段时,还没来得及获取大多数决策者 (Acceptor) 的最终同意,大多数决策者 (Acceptor) 就被别的提议者 (Proposer) 进行策反了,无奈只能有回到第一阶段,如此循环反复。


针对上述的问题,即我们如何保证Paxos算法的活性,在实际环境中会通过一次提议,选择一个Leader,后续所有的提议都只能由Leader提出,就可以保证Paxos算法的活性。

发布了286 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/newbie0107/article/details/105013792