Overview

  • Paxos算法介绍

问题和假设

  • Paxos算法解决的问题是,在不考虑出现消息篡改(即拜占庭错误)的情况下,如何在一个可能发生异常(消息延迟、丢失,进程慢、被杀死、重启等)的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。
  • Lamport最初在引入该算法的时候,举了一个有意思的例子来描述问题场景:
    在一个叫Paxos的小岛上,岛上采用议会的形式来通过法令,议会中的议员通过信使进行消息的传递。同时要注意议员和信使随时有可能会离开议会厅,并且信使可能会重复传递消息,也可能一去不复返。因此,议会协议要保证在这种情况下法令仍然能够正确的产生,并且不会出现冲突

算法

算法的提出与证明

算法角色

  • 首先,介绍算法中的几大角色:
    • proposers:提出提案,提案信息包括提案编号和提议的value;
    • acceptors:收到提案后可以接受提案,被多数Acceptor接受的提案会被批准(关于“多数”在后面会有进一步介绍)
    • learners:只能“学习”被批准的提案,但learners可以身兼数职。
  • 划分角色后,就可以更精确地定义问题:
    1. 决议(value)只有在被proposers提出后才能被批准;
    2. 在一次Paxos算法的执行实例中,只批准一个value;
    3. learners只能获得被批准的value
  • 作者通过不断加强上述三个约束(主要是第二个),获得了Paxos算法。
    • 为了满足只批准一个value的约束,要求经“多数派(majority)”接受的value称为正式的决议。两组majority至少有一个公共的acceptor,如果每个acceptor只能接受一个value,约束2就能保证。这就产生了一个显而易见的新约束:
      P1: 一个acceptor必须接受第一次收到的提案。
    • 但是P1不是完备的。如果恰好一半acceptor接受的提案具有valueA,另一半valueB,那么就无法形成majority,无法批准任何一个value。
    • 约束并不要求只批准一个提案,暗示可能存在多个提案,只要提案的value是一样的。于是可以产生P2: (注意value和提案的不同)
      P2: 一旦一个具有value v的提案被批准,那么之后批准的提案必须具有value v
      注:通过某种方法(这不包括在Paxos算法之内)可以为每个提案分配一个编号,在提案之间建立一个全局关系,所谓”之后”都是指所有编号更大的提案。
    • 如果P1和P2都能保证,那么约束2就能保证。批准一个value意味着多个acceptor接受了该value。因此,可以对P2进行加强。
      P2a: 一旦一个具有value v的提案被批准,那么之后任何acceptor再次接受的提案必须具有value v。(P2a实际上就是P2的加强版)
    • 由于通信是异步的,P2a和P1会发生冲突。如果一个value被批准后,一个proposer和一个acceptor从休眠中苏醒,前者提出一个具有新的value的提案。根据P1,后者应当接受,根据P2a,则不应当接受。这种场景下P2a和P1有矛盾。于是需要换个思路,转而对proposers的行为进行约束。
      P2b: 一旦一个具有value v的提案被批准,那么以后任何proposer提出的提案都必须具有value v
      由于acceptor能接受的提案必须由proposer提出,所以P2b蕴涵了P2a,是一个更强的约束。
    • 但是根据P2b难以提出实现手段,因此需要进一步加强P2b。假设一个编号为m的value v以及被chosen(批准),来看看在什么情况下对任何编号n(n > m)的提案都含有value v。因为m已经被批准,显然存在一个acceptors的多数派C,它们都接受了v。考虑到任何多数派和C都至少有一个公共成员,可以找到一个蕴含P2b的约束P2c:
      P2c: 如果一个编号为n的提案具有value v,那么至少存在一个多数派,要么它们所有人都没有接受编号小于n的任何提案,要么它们已经接受了所有编号小于n的提案中编号最大的那个提案具有value v。
      可以用数学归纳法证明P2c蕴含P2b(略)。

决议的提出与批准

  • 通过一个决议分为两个阶段:
    • prepare阶段:
      1. proposer选择一个提案编号n,并将prepare请求发给acceptors中的一个多数派;
      2. acceptor收到prepare请求后,如果提案的编号大于它已经回复的所有prepare消息,则acceptor将自己上次接受的提案回复给proposer,并承诺不再回复小于n的提案;
    • chosen阶段
      1. 当一个proposer收到了多数acceptors对prepare的回复后,就进入批准阶段。它要向回复prepare请求的acceptors发送accept请求,包括编号n和根据P2c决定的value(如果根据P2c没有已经接受的value,那么它可以自由决定value)
      2. 在不违背自己向其他proposer的承诺的前提下,acceptor可以收到accpet请求后接受这个请求。
  • 在这个过程中,任何时候中断都可以保证正确性。例如如果一个proposer发现已经有其他proposers提出了编号更高的提案,则有必要中断这个过程。因此为了优化,在上述prepare过程中,如果一个acceptor发现存在一个更高编号的提案,则需要通知proposer,提醒中断这次提案。

提案的获取

  • 接下来看learners如何获取提案。

方案一

  • learner获取一个提案的前提是,该提案已被半数以上的acceptor批准。因此,最简单的做法就是一旦acceptor批准了一个提案,就将该提案发送给所有的learner
  • 显然,该做法虽然可以让learners尽快地获取被选定的提案,但是却需要让每个acceptor与所有的learner逐个进行一次通信,因此通信次数至少为二者个数的乘积。

方案二

  • 可以让所有的acceptor将它们对提案的批准情况,统一发送给一个特定的learner(称为“主”learner),在不考虑拜占庭问题的前提下,我们假定learner之间可以通过消息通信来互相感知提案的选定情况。基于此,主learner被通知一个已被选定的提案时,它会负责通知其他的learner。
  • 该方案大大减少了通信量,但引入了新的不稳定因素:主learner随时可能出现故障。

FYI