分布式一致性协议 --- Paxos

    问题

  • Paxos 到底解决什么样的问题,动机是什么
  • Paxos 流程是怎么样的?
  • Paxos 算法的缺陷是什么

概述

          Paxos 是分布式一致性算法,根据少数服从多数的原则多个节点确定某个数值。通过学习 Base Paxos ,我们再进一步优化,提出了 Multi Paxos .

动机

         我们先思考为什么会出现一致性问题,原因是我们原本使用一台机器,而使用多台机器后(分布式),发生网络延迟或是其他原因导致所有机器不能同时在线,分布式的好处为了让我们享有可用性的好处,但是多台同时也会带来一致性的问题,最好理解的就是MySQL 中的主从复制,当主在写入的时候从没来得及复制完毕,那么此时的读到的数据是和刚写入的值是不一致的,而过多一会再次读就可以读到正确的值,也就是上面讲到的主从复制保证的最终一致性,于是,起码来说分布式中要解决这两个问题 :

  • 部分机器挂了
  • 一致性问题

我们来看一下wiki中关于 Paxos 的介绍 :

Paxos is a family of protocols for solving consensus in a network of unreliable processors (that is, processors that may fail). Consensus is the process of agreeing on one result among a group of participants. This problem becomes difficult when the participants or their communication medium may experience failures.[1]

Consensus protocols are the basis for the state machine replication approach to distributed computing, as suggested by Leslie Lamport[2] and surveyed by Fred Schneider.[3] State machine replication is a technique for converting an algorithm into a fault-tolerant, distributed implementation. Ad-hoc techniques may leave important cases of failures unresolved. The principled approach proposed by Lamport et al. ensures all cases are handled safely.

来自 <https://en.wikipedia.org/wiki/Paxos_(computer_science)#Typical_deployment>

        所以该算法的最终目的是在节点出现问题的情况下保持一致性,关于另外一个理解Paxos 存在的动机可以看这一篇文章

Paxos 协议过程

       下面的推导过程来自 <https://www.cnblogs.com/bangerlee/p/5655754.html> ,非原创

        Paxos 协议的包含三个角色 :

  • Proposer
  • Acceptor
  • Learner

       协议开始之前我们思考一个问题,当面对多个节点协议而达到一致性的情况,第一个想到的解决方案是什么?少数服从多数。Paxos 协议的思路实际就是少数服从多数。

       和2PC类似,Paxos先把节点分成两类,发起提议(proposal)的一方为proposer,参与决议的一方为acceptor。假如只有一个proposer发起提议,并且节点不宕机、消息不丢包,那么acceptor做到以下这点就可以确定一个值:

P1. 一个acceptor接受它收到的第一项提议

        当然上面要求的前提条件有些严苛,节点不能宕机、消息不能丢包,还只能由一个proposer发起提议。我们尝试放宽条件,假设多个proposer可以同时发起提议,又怎样才能做到确定并只确定一个值呢?

首先proposer和acceptor需要满足以下两个条件:

1. proposer发起的每项提议分别用一个ID标识,提议的组成因此变为(ID, value)

2. acceptor可以接受(accept)不止一项提议,当多数(quorum) acceptor接受一项提议时该提议被确定(chosen)

(注: 注意以上“接受”和“确定”的区别)

      我们约定后面发起的提议的ID比前面提议的ID大,并假设可以有多项提议被确定,为做到确定并只确定一个值acceptor要做到以下这点:

P2. 如果一项值为v的提议被确定,那么后续只确定值为v的提议

(注: 乍看这个条件不太好理解,谨记目标是“确定并只确定一个值”)

       由于一项提议被确定(chosen)前必须先被多数派acceptor接受(accepted),为实现P2,实质上acceptor需要做到:

P2a. 如果一项值为v的提议被确定,那么acceptor后续只接受值为v的提议

       满足P2a则P2成立 (P2a => P2)。目前在多个proposer可以同时发起提议的情况下,满足P1、P2a即能做到确定并只确定一个值。如果再加上节点宕机恢复、消息丢包的考量呢?假设acceptor c 宕机一段时间后恢复,c 宕机期间其他acceptor已经确定了一项值为v的决议但c 因为宕机并不知晓;c 恢复后如果有proposer马上发起一项值不是v的提议,由于条件P1,c 会接受该提议,这与P2a矛盾。为了避免这样的情况出现,进一步地我们对proposer作约束:

P2b. 如果一项值为v的提议被确定,那么proposer后续只发起值为v的提议

        满足P2b则P2a成立 (P2b => P2a => P2)。P2b约束的是提议被确定(chosen)后proposer的行为,我们更关心提议被确定前proposer应该怎么做:

P2c. 对于提议(n,v),acceptor的多数派S中,如果存在acceptor最近一次(即ID值最大)接受的提议的值为v',那么要求v = v';否则v可为任意值

        满足P2c则P2b成立 (P2c => P2b => P2a => P2)。

        以上提到的各项约束条件可以归纳为3点,如果proposer/acceptor满足下面3点,那么在少数节点宕机、网络分化隔离的情况下,在“确定并只确定一个值”这件事情上可以保证一致性(consistency):

  • B1(ß): ß中每一轮决议都有唯一的ID标识
  • B2(ß): 如果决议B被acceptor多数派接受,则确定决议B
  • B3(ß): 对于ß中的任意提议B(n,v),acceptor的多数派中如果存在acceptor最近一次(即ID值最大)接受的提议的值为v',那么要求v = v';否则v可为任意值

(注: 希腊字母ß表示多轮决议的集合,字母B表示一轮决议)

      另外为保证P2c,我们对acceptor作两个要求:

1. 记录曾接受的ID最大的提议,因proposer需要问询该信息以决定提议值

2. 在回应提议ID为n的proposer自己曾接受过ID最大的提议时,acceptor同时保证(promise)不再接受ID小于n的提议

        至此,proposer/acceptor完成一轮决议可归纳为prepare和accept两个阶段。prepare阶段proposer发起提议问询提议值、acceptor回应问询并进行promise;accept阶段完成决议,图示如下:

clip_image001


上面我们对协议进行了推导,下面用文字表述一下这个过程 :

阶段1.

  1. proposer 选择一个提案编号Mn,向acceptor的多数派发送编号为Mn的prepare请求。
  2. acceptor:如果接收到编号为Mn 的prepare请求,并且Mn大于它已经回应的任何prepare请求,它就返回已经批准的编号最高的提案的value(如果有的话),并承诺不再批准任何编号小于Mn的提案。

    阶段2.

  1. proposer :如果收到了多数acceptor对prepare请求Mn的回应,它就向这些Acceptor发送提案[Mn, Mv]的accept请求,其中Mn是所有prepare请求回应中编号最大的已批准提案的value;或者是proposer 选择的值,如果所有prepare请求的响应均没有带回已批准的提案。
  2. acceptor:如果收到了提案[Mn, Mv]的accept请求,它就批准该提案,除非它已经回应了一个编号大于Mn的提案。

       其中,Mn是提案编号。

可能出现的问题

        还有一个问题需要考量,假如proposer A发起ID为n的提议,在提议未完成前proposer B又发起ID为n+1的提议,在n+1提议未完成前proposer C又发起ID为n+2的提议…… 如此acceptor不能完成决议、形成活锁(livelock),虽然这不影响一致性,但我们一般不想让这样的情况发生。解决的方法是从proposer中选出一个leader,提议统一由leader发起。

paxos死锁的情况出现

        上图来自 wiki。

Multi Paxos

          上面我们知道在第一阶段中prepare 的目的是为了获取最新的提案编号,并且这个过程只能确定一个值。并且Base Paxos 中多个 proposer 发送多个消息,最终只有一个提案通过,大量的信息都是浪费的,Multi Paxos 中只使用一个 proposer 。

  • 选主状态,由集群中的任意节点拉票发起选主,拉票中带上自己的vx,通过收集集群中半数以上的Vn,来更新自己的Vc 值,得到目前集群通过的最大Vc = Vn
  • 强leader状态,leader对Vn的演变了如指掌,每次把Vn的值直接在一阶段中发送给acceptor,和basic paxos的区别:basic paxos一阶段的时候,proposer对vn的值一无所知,要依赖一阶段的结果来算 Vn

我们把单次“确定一个值”的过程称为实例(instance),它由proposer/acceptor/learner组成,下图说明了A/B/C三机上的实例:

不同序号的实例之间互相不影响,A/B/C三机输入相同、过程实质等同于执行相同序列的状态机(state machine)指令 ,因而将得到一致的结果。

proposer leader在Multi Paxos中还有助于提升性能,常态下统一由leader发起提议,可节省prepare步骤(leader不用问询acceptor曾接受过的ID最大的提议、只有leader提议也不需要acceptor进行promise)直至发生leader宕机、重新选主。

         

参考资料

猜你喜欢

转载自www.cnblogs.com/Benjious/p/11318451.html