对Paxos协议的介绍,可以通过Leslie Lamport的《Paxos Made Simple》展开学习和了解。Paxos算法在允许失败的分布式系统环境下,实现系统一致性。失败的情况有很多,譬如由于网络问题导致的通信数据丢失,参与Paxos算法的机器宕机等情况。Paxos算法将分布式系统一致性问题进行抽象,用以解决以下问题:
假设有一群进程,这些进程可提出一些value。使用一种一致性算法,从这些被提出的value中选出唯一一个值value。如果这些进程没有提出过value,那么就说明没有value需要被选出。反之,如果一个value被选出,那么这些进程就需要接受这个value。在此问题上,需要有几个要求需要被满足:
- 仅当一个value被提出之后才有可能选中该value。
- 在整个算法过程中,仅有一个value会被选中。
- 除非一个value被选中,否则任何一个进程都不会知道会选中哪个value。
这里的value可能是任何的消息数据。譬如在分布式系统中选举leader的过程中,value就可以是标记leader的身份标识;譬如在分布式数据库中,value可能是一次操作日志(实际上Paxos算法的整个过程只能选举出唯一一个value,像数据库操作日志这样随时间迁移而变化的值,应该在Paxos算法基础之上加以修改,才能满足需求,譬如multi-Paxos)
参与Paxos算法过程*有三种角色,这三种角色可以在一个进程中同时存在:
- 提议者(Proposer) 该角色的职能为提出value。
- 投票者(Acceptor) 该角色的职能为参与选择value的过程。
- 学习者(Learner) 该角色的职能为接受value。
Paxos算法证明
一个提议者(Proposer)将会发送一个提议(Proposal)给一群投票者(Acceptors)。当一个投票者(Acceptor)获取到一个提议(Proposal)后,可能接受(accept)该提议(Proposal),也可能拒绝该提议。当一个提议获取了大多数投票者的接受(accept)之后,则认为该提议(Proposal)被选中。
在不保证数据可靠传输的网络环境下,为保证Paxos能够实现一致性需求,因此设定一个要求:
\(P1.\) 一个投票者(Proposer)必须接受(accept)他收到的第一个提议(Proposal)。
但是该要求隐含了一个问题,当多个提议者(Proposers)同时提出多个提议(Proposal)后,每个投票者(Acceptor)都会收到一个提议(Proposal),但可能极有不存在一个“大多数”的投票者(Acceptor)具备相同的提议(Proposal)。因此无法选择其中一个被“大多数”投票者(Acceptors)接受(access)的值。因此一个投票者(Acceptor)必须允许接受(accept)多于一个的提议(Proposal)。为了区分不同的提议(Proposal),因此一个提议(Proposal)应包含一个序号和一个value。不同的提议(Proposal)具有不同的序号。
我们应允许多个提议(Proposal)被选中,但是必须保证这些提议(Proposal)具有相同的value。可通过提议(Proposal)中的序号来保证这个需求的实现:
\(P2\) 如果一个提议(Proposal)的value \(v\)被选中,那么算法后续执行过程中大于这个提议(Proposal)序号的提议(Proposal)若被选中,那么这个后续被选中的提议(Proposal)的value也为 \(v\)
在此条件下,保证了只有单一的value会被选中。要求提议(Proposal)的序号必须是有序的。为了一致性,提议(Proposal)必须至少被一个投票者(Acceptor)接受(accept),因此满足\(P2\)的要求需要满足:
\(P2^a\) 如果一个提议(Proposal)的value \(v\)被选中,那么在算法后续执行过程中,任何一个投票者(Acceptor)所接受的高于当前提议(Proposal)序号的提议(Proposal)中,value的值也为\(v\)
由于一个提议(Proposal)可能被一些没有接受过任何提议(Proposal)的投票者(Acceptor)所接受(accept)。根据\(P1\)的要求,这个投票者(Acceptor)需要接受这个提议(Proposal),但是却违背了\(P2^a\),因此需要对\(P2^a\)进行加强:
\(P2^b\) 如果一个提议(Proposal)的value \(v\)被选中,那么之后每一个提议者(Proposer)发出的高于当前提议(Proposal)序号的提议(Proposal)中,value都为\(v\)。
假设有一些提议(Proposal)已经被选中,证明任何序号n > m的提议(Proposal)的value都为\(v\):
假设每个发出序号在 \([m, n-1]\)之间的提议(Proposal)都具有value \(v\)。既然序号为m的提议(Proposal)被选中了,那么必然有一个集合C,它由“大多数”接受(accept)\(v\)的投票者(Acceptor)组成,可以推出:C中每个投票者(Acceptor)都接受(accept)了序号在\([m,n-1]\)中的一个提议(Proposal),被C中任意一个投票者(Acceptor)所接收(accept)的序号在\([m, n-1]\)中的提议(Proposal)的value都是\(v\)。 因为任何由“大多数”投票者(Acceptor)组成的集合S必然和C存在公共元素。可以通过满足以下条件来确保序号为n的提议(Proposal)的value为\(v\)。
\(P2^c\) 对于任意的n和v,如果一个由n和v组成的提议(Proposal)被发出。存在一个由“大多数”投票者(Acceptor)组成的集合S,要么(a)S中没有一个投票者(Acceptor)接受(accept)序号小于n的提议(Proposal);要么(b)S中的投票者(Acceptor)接受(accept)与当前提议(Proposal)中value相同的提议(Proposal),并且这些已经接受过的提议(Proposal)的最大序号都小于n。
获取已经被接受(accept)的提议(Proposal)非常简单,但是对未来的接受(accept)情况的预测非常困难。为了避免对未来进行预测,提议者(Proposer)通过承诺(Prepare)的方式来实现控制。换句话说,提议者(Proposer)通过预案(Prepare)和承诺(Promise)的方式来与投票者(Acceptor)达成共识:不要接受任何小于n的提议(Proposal)。
Paxos流程说明
Paxos算法执行过程将分为两个阶段。
在第一个阶段过程中,可称为算法的预备阶段:
- 提议者(Proposer)向投票者发起预案(Prepare),预案携带\(K\)值,\(K\)值及预案提出的提议(Proposal)的序号,序号递增并且不能重复,提议者(Proposer)通过预案(Prepare)告知投票者,不要接受(accept)小于\(K\)的提议(Proposal)。
- 投票者(Acceptor)获取到预案(Prepare)后,根据自身已经获取到的提议(Proposal)执行相关操作。
a) 如果投票者(Acceptor)尚未接受(accept)过任何提议(Proposal),则向提议者(Proposer)反馈承诺,承诺该投票者(Acceptor)不再接受小于K的提议(Proposal);
b) 如果投票者(Acceptor)接受过提议(Proposal),取接受过的提议(Proposal)中序号\(K_{Max}\)最大的提议进行进一步分析,如果\(K_{Max} > K\),那么投票者(Acceptor)将告知该提议者(Proposal)拒绝该预案(Prepare); 如果\(K_{Max} < K\) 那么投票者将\(K_{Max}\)的值设置为 \(K\),并将已经接受(accept)过的最大序号的提议(Proposal)封装成为承诺(Promise)返回给投票者(Proposer)。
第二个阶段可称为算法的选举阶段:
- 提议者(Proposer)收到了投票者(Acceptor)发来的响应,如果响应有超过半数的承诺(Promise),则进一步分析:如果回复的承诺(Promise)中全部没有包含之前的提议(Proposal),则将value和预案(Prepare)中的序号K打包成为提议(Proposal)发送给投票者(Acceptor);如果回复的承诺(Promise)中存在之前的提议(Proposal),则将这些之前的提议(Proposal)中最大序号的提议(Proposal)中的value与序号K打包成为提议(Proposal)发送给投票者(Acceptor)。如果回复的承诺(Promise)没有超过半数,则递增序号K,重新执行算法的预备阶段。
- 投票者(Acceptor)若收到提议者(Proposer)发来的提议(Proposal)。首先进行判断发来的提议(Proposal)中序号\(K\)与自身之前接受的提议(Proposal)中最大序号\(K_{Max}\)进行比较:如果\(K < K_{Max}\) 则发回拒绝响应;如果 \(K >= K_{Max}\) 则将\(K_{Max}\)的值设置为\(K\),将\(V_{Max}\) 设置为 \(V\) 并返回接受(accept)响应告知提议者(Proposer)。
- 若提议者(Acceptor)获取到超过半数的接受(accept),则将\(V\)告知所有的学习者(Learner);若提议者(Acceptor)没有获取到超过半数的接受(accept),则重新发起预备阶段。