通过实例来理解paxos算法

背景

  Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的”La”,此人现在在微软研究院)于1990年提出的一种基于消息传递的一致性算法。由于算法难以理解起初并没有引起人们的重视,使Lamport在八年后重新发表到TOCS上[2]。即便如此paxos算法还是没有得到重视,2001年Lamport用可读性比较强的叙述性语言给出算法描述[3]。可见Lamport对paxos算法情有独钟。近几年paxos算法的普遍使用也证明它在分布式一致性算法中的重要地位。06年google的三篇论文初现“云”的端倪,其中的chubby锁服务使用paxos作为chubby cell中的一致性算法,paxos的人气从此一路狂飙。

什么是paxos算法

  Paxos 算法是分布式一致性算法用来解决一个分布式系统如何就某个值(决议)达成一致的问题。一个典型的场景是,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态1。为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个”一致性算法”以保证每个节点看到的指令一致。

paxos干啥的

  分布式系统中一般是通过多副本来保证可靠性,而多个副本之间会存在数据不一致的情况。所以必须有一个一致性算法来保证数据的一致,描述如下: 
  假如在分布式系统中初始是各个节点的数据是一致的,每个节点都顺序执行系列操作,然后每个节点最终的数据还是一致的。 
  Paxos算法就是解决这种分布式场景中的一致性问题。对于一般的开发人员来说,只需要知道paxos是一个分布式选举算法即可。多个节点之间存在两种通讯模型:共享内存(Shared memory)、消息传递(Messages passing),Paxos是基于消息传递的通讯模型的。

paxos算法介绍

Paxos保证以下三点: 
1. 只有被提出提案才能被选定; 
2. 只有一个值被选定; 
3. 如果某个进程认为某个提案被选定了,那么这个提案必须是真的被选定的那个。 
该一致性算法中有三个角色,分别是:proposer,acceptor,learner。它们之间通过消息来通讯。

paxos算法的两阶段 
prepare 阶段: 
  1. Proposer 选择一个提案编号 n,然后向acceptor的某个超过半数的子成员发送编号为n的 prepare 请求; 
  2. Acceptor 收到 prepare 消息后,如果提案的编号n大于该acceptor已经回复的所有 prepare 请求的编号,则 Acceptor 将自己上次已经批准的最大编号提案回复给 Proposer,并承诺不再回复小于 n 的提案;

acceptor阶段: 
  1. 当一个 Proposer 收到了半数以上的 Acceptors 对 prepare 的回复后,就进入批准阶段。它要向回复 prepare 请求的 Acceptors 发送 accept 请求,包括编号 n 和根据 prepare阶段 决定的 value。这里的value是所有响应中编号最大的提案的value(如果根据 prepare 没有已经接受的 value,那么它可以自由决定 value)。 
  2. 在不违背自己向其他 Proposer 的承诺的前提下,Acceptor 收到 accept 请求后即接受这个请求。即如果acceptor收到这个针对n提案的accep请求,只要改acceptor尚未对编号大于n的prepare请求做出过响应,它就可以通过这个提案。

流程图如下2: 

具体实例 
首先,给出proposer和acceptor的消息图3: 

针对上面提出的两个阶段,分别解释: 
prepare阶段 
1. 
  每个server向proposer发送消息,表示自己要当leader,假设proposer收到消息的时间不一样,顺序是: proposer2 -> proposer1 -> proposer3,消息编号依次为1、2、3。 
  紧接着,proposer将消息发给acceptor中超过半数的子成员(这里选择两个),如图所示,proposer2向acceptor2和acceptor3发送编号为1的消息,proposer1向acceptor1和accepto2发送编号为2的消息,proposer3向acceptor2和acceptor3发送编号为3的消息。 
2. 
  假设这时proposer1发送的消息先到达acceptor1和acceptor2,它们都没有接收过请求,所以接收该请求并返回【2,null】给proposer1,同时承诺不再接受编号小于2的请求; 
  紧接着,proposer2的消息到达acceptor2和acceptor3,acceptor3没有接受过请求,所以返回proposer2 【1,null】,并承诺不再接受编号小于1的消息。而acceptor2已经接受proposer1的请求并承诺不再接收编号小于2的请求,所以acceptor2拒绝proposer2的请求; 
  最后,proposer3的消息到达acceptor2和acceptor3,它们都接受过提议,但编号3的消息大于acceptor2已接受的2和acceptor3已接受的1,所以他们都接受该提议,并返回proposer3 【3,null】; 
  此时,proposer2没有收到过半的回复,所以重新取得编号4,并发送给acceptor2和acceptor3,此时编号4大于它们已接受的提案编号3,所以接受该提案,并返回proposer2 【4,null】。

accept阶段 

  Proposer3收到半数以上(两个)的回复,并且返回的value为null,所以,proposer3提交了【3,server3】的提案。 
  Proposer1也收到过半回复,返回的value为null,所以proposer1提交了【2,server1】的提案。 
  Proposer2也收到过半回复,返回的value为null,所以proposer2提交了【4,server2】的提案。 

  Acceptor1和acceptor2接收到proposer1的提案【2,server1】,acceptor1通过该请求,acceptor2承诺不再接受编号小于4的提案,所以拒绝; 
  Acceptor2和acceptor3接收到proposer2的提案【4,server2】,都通过该提案; 
  Acceptor2和acceptor3接收到proposer3的提案【3,server3】,它们都承诺不再接受编号小于4的提案,所以都拒绝。 
  此时,过半的acceptor(acceptor2和acceptor3)都接受了提案【4,server2】,learner感知到提案的通过,learner开始学习提案,所以server2成为最终的leader。

 

一些不错的参考资料 
lamport的两篇论文: 
Lamport, The part-time parliament, ACM Transactions on Computer Systems 16(2):133-169, 1998 
Lamport, Paxos made simple, SIGACT News 32(4):18-25, 2001. 
其他: 
http://chuansong.me/n/1050231 
http://www.cnblogs.com/ychellboy/archive/2009/12/29/1634801.html

转载:Summer_ZJU

posted @ 2017-08-03 15:07  明志健致远  阅读(...)  评论(...编辑  收藏