您的位置:首页 > 其它

兼职议会

2013-10-09 20:52 381 查看

1.数据一致性

在一个完全分布式存储系统中,如何保证结点之间的一致性是非常重要的问题。所谓一致性指的是用户从系统中读取的数据不存在冲突。这种读的一致性必然会依赖于写的一致性,即存储系统中数据本身不存在冲突。

Lamport为我们描述了如何确保存储系统的读写一致性,称为Paxos协议。描述的方式非常独特,作者化身为考古学家,透过Paxon文明的议会运行机制阐述了Paxos协议的本质。Paxos协议最重要的目标是确保大家能达成一致,而优化工作是如何更快地达成一致。

2.什么样的议会

Lamport首先介绍了这个议会的特点,这些特点与现代的分布式存储系统很像,很容易产生联想,下面括号内表明了其在存储系统中的含义。

议会(一个全对等的分布式存储系统)是由一群议员(结点)组成的,议员的职责是确定法律(存储数据),每个法律提案(写操作)只要得到半数以上议员的同意就算通过。议员很少拒绝一个法律的通过(结点不会随意拒绝存储某些数据)。每个议员都有一个账本(存储介质)用于记录被通过的一系列法律。议员可能随时离开会议(结点可能会失效),为了避免离开会议后忘记自己的任务,议员在账本的背面记下笔记(日志)。账本上的法律不允许被修改,但是笔记可以擦除。议员也有计时器可以知道会议的时间(判断是否超时)。议员会将不那么重要的笔记记录在纸上(内存),离开会议就会丢失纸上的信息。议会的音响很差,因此不能演讲(没有中心结点)。议员只能通过信使(交换机)交流。信使也随时可能离开会议(交换机失效),因此它可能丢失传递的信息,但是它绝不会传递错误的信息(链路可靠)。虽然议员和信使可能随时离开(存储结点和交换机都有失效的风险),但是他们在场时都尽职尽责。议员可能出现不诚实的行为(安全问题),但很少见。议员和人民(客户端)随时可以查询法律(读操作)。

保证各个账本之间的一致性是议会的基本要求。不论出现何种意外(比如,议员、信使突然离开),可以有个别账本没有及时更新,但是决不允许出现冲突(写一致性),比如第132号法律在不同的账本上不同。人们查询法律时,不允许读到过时的信息(读一致性)。

为了保证一致性,议会必须遵循一定的协议。这个协议必须保证只要有足够多的议员停留足够长的时间,法律一定会通过(只要失效的结点不过多,数据迟早会更新)。

3.单法令Synod协议

Paxon的牧师们每19年需要举行会议,通过一个法令。牧师们面临和议员们完全一样的困境,因此数学家通过四个步骤设计Synod协议:首先,证明协议满足什么样的条件就能保证一致性;然后,循序渐进地设计出初始协议、基础协议和完整协议。Paxos协议是从Synod协议衍生的。

3.1.限制条件

牧师通过一系列的投票(ballot)确定法令。每次投票都只针对一个法令提案,参与的牧师可以选择投票(赞成),或者不投票(不投票的原因通常是缺席或者别的客观原因)。每次投票都指定一个法定牧师团(quorum),它是全体牧师的非空子集。当且仅当法定牧师团的所有牧师都投了票,该次投票才算成功,法令通过。每次投票由四部分组成:

B_dec,投票的法令;

B_qrm,法定牧师团;

B_vot,投票的牧师;

B_bal,投票的编号。

编号暗示了投票逻辑上的顺序,但是并不表示实际发生的顺序。曾经发生的所有投票组成投票集合ß。数学家证明了只要投票集合满足三个条件,就能保证一致性。

每次投票的编号唯一;

任意两次投票的法定牧师团都有相同的牧师;

对于任意一次投票,如果它的法定牧师团中有人曾经投过票,找出其中最晚(编号最大)的一次投票,本次投票的法令必须和最晚投票的法令相同。

第二条规定法定牧师团必须有足够多的牧师,这样才满足大多数牧师赞成的条件。第三条保证牧师最终会达成一致,因为一旦投票成功了(所有牧师都投票,法令通过),那么后续投票的法令不再变化,论文中给出了详细的证明。

3.2.初始协议

基于三个条件可以直接推导出初级协议,初级协议规定了一次投票的发起、运行和结束。

每次投票都是由某个牧师发起的,他需要为投票选择编号,法令,和法定牧师团。为了保证编号的唯一性,编号由<本地编号, 牧师名称>构成,这样牧师只要保证编号不与自己曾经发起的投票重复就行了。编号的排序可以先根据本地编号,再根据牧师名称的字母顺序。为了满足条件2,选定的法定牧师团必须包含大部分牧师。大部分不一定指数量上的大部分,可以为每位牧师分配不同的权值(威望,出勤率等)。保证条件3需要询问法定牧师团的每位成员,成员收到询问后,反馈自己投赞成票的投票编号中最大的一个,牧师根据这些反馈意见决定此次需要投票的法令(如果这是第一次投票,则法令可以任意)。这样,发起一次投票包括两步:

牧师p选择一个编号b,并向在场的大部分牧师发送NextBallot(b)信息。

牧师q收到NextBallot(b)信息后,反馈一个LastVote(b, v)信息,其中v是q曾经投赞成票的投票编号中小于b的最大的一个。

每位牧师必须记录下自己曾经投过赞成票的投票编号。当q发送了LastVote信息后,可能还会收到新的投票请求,q必须忽略所有编号在(v,b)之间投票,否则将破坏第三个条件。值得注意的是,选择v时并没有要求是最大的一次投票,可能存在比b大的投票,这时再进行b投票肯定会破坏条件3,所以需要在下面的步骤中避免这种情况。接下来的两个步骤:

p收到牧师的LastVote回复后,可以根据回复的情况确定法定牧师团,以及此次投票的法令d。p将该投票的发起信息记录在账,然后向法定牧师团发送BeginBallot(b, d)信息。

牧师q收到BeginBallot(b, d)后,决定是否要投票,q可能因为投票会违反其它LastVote承诺而放弃投票(比如发现有大于b的投票)。如果决定投票,就反馈Voted(b,q),并且记录这次投票在帐。

为了保证条件3,牧师可以拒绝投票,比如他发现已经有一个比b大的投票存在,或者存在另一个LastVote(b’,v),其中b’大于b。上述的任何步骤都是可选的,也就是说错过任何步骤都只会使得本次投票失效,拖延会议进度,而不会产生任何不一致。协议还剩下两步:

如果p收到了每位牧师的Voted(b,q)信息,那么投票成功了,法令通过。p记录法令在帐,并发送Success(d)给所有牧师(不止法定牧师团,是所有)。

牧师收到Success(d)后,记录d在帐。

初始协议允许任何牧师在任意时刻发起新的投票。协议满足三个条件,所以确保一致性。然而,初始协议不保证会议能取得实质性进展。

因为牧师可以同时发起多次投票,初始协议要求每位牧师记录下自己曾经发起过的每次投票,而不是最近的一次投票;为了产生LastVote,牧师必须找到小于b的最大的一次投票,因此要求牧师记录投过的每次票的编号记录发送过的所有LastVote信息,这样才能判断一次投票是否违反某个LastVote承诺。协议其实满足了投票的单调性,如果已经存在b’,大于当前投票b,那么b必然会落入某个LastVote的承诺中,而无法成功。

3.3.基础协议

基础协议在初始协议上增加了新的约束,利用单调性进行优化。首先,每位牧师每次只能发起一次投票,因此无需再记录发起的每次投票编号,取而代之的,仅记录最近发起的投票编号lastTried,在发起了一次投票后,牧师忽略任何它先前发起的投票的信息;其次,基础协议的LastVote承诺更严格,小于b的投票都不允许(在初始协议,是(v,b)之间的投票不允许),因此基础协议只需记录上次投票的编号prevVote以及下次投票的编号nextBal(共同组成了一个LastVote承诺)。

修改过后的协议如下:

牧师p选择一个大于lastTried的投票编号b,并用lastTried记录新编号,向大部分牧师发送NextBallot(b)。

牧师q收到NextBallot(b)后,如果b大于自己的nextBal,则更新nextBal为b,反馈LastVote(b,v),其中v等于prevVote(如果b小于nextBal,则忽略)。

牧师p收到LastVote(b,v)后,确定法定牧师团(如果收到的LastVote数量不到大多数的标准,投票取消)和法令d,d的选择遵从条件3。向法定牧师团发送BeginBallot(b,d)。

牧师q收到BeginBallot(b,d)后,与自己的nextBal比较,确定相等后,q更新prevVote为b,反馈Voted(b,q)。(不相等就忽略)

如果牧师p收到法定牧师团的所有Voted(b,q)信息,并且b等于他的lastTried,那么投票成功了,将法令记录在账,并发送Success(d)给每个牧师。

收到Success(d),牧师将法令记录在账。

基础协议根据单调性进行了优化,节约了资源。基础协议仍然遵守了三个条件,因此保证一致性。然而基础协议仍然无法保证会议的实质进展。比如多个牧师同时发起投票,他们将互相冲突,导致没有一次投票会成功。进一步的优化就包括如何选举一个牧师发起投票,以及发起投票的频率。

3.4.完整协议

完整协议的流程和基础协议是一致的,但是进一步加强了约束。永远不发起投票当然保证了一致性,但会议永远不可能取得进展。同时发起太多的投票同样也阻碍会议进展。因此,完整协议设计了一个选举算法并规定了发起投票的频率,具体回答哪个牧师(总统)在何时应该发起投票的问题。

为了保证进展,牧师应该等上一次投票结束才开始新的投票。这就需要估计信息的传递时间和处理时间。假定信息传递需要4分钟,处理需要7分钟,那么一次成功的交互大概需要22分钟,成功跑完整个协议55分钟。如果超时了,牧师可以发起新的投票。

如果一段时间内没有人进出议会,选举算法的目标是在T时间内确定一个总统。一个最简单的方法是牧师定时向其他牧师发送自己的名字,如果没有得到其他牧师的更高排位的名字,这个牧师就自认为是总统。暂时存在多个总统只会影响会议进程而不会影响一致性。

4.多法令Paxos协议

根据Synod可以比较容易推出Paxos协议,每个法令对应一个Synod协议实例,按顺序执行Synod协议即可,当然里面还有大量优化技术。

5.体会

我觉得在理解作者的思想时,一定不要去纠结议会选举的细节,比如有议员反对该怎么办。在Paxos协议中,议员反对和议员缺席是一样的,而且在计算机系统中不存在类似的问题,所以作者特意强调了“议员乐于通过所有的提案”。过分考虑这些问题会使得理解复杂化,反而忽略了协议的本质“一致性”。

其实Paxos协议的思想还是很简单的:在一个全对等的存储集群,先选举一个总统,所有的写请求都会分发给各个结点(NextBallot),在线结点反馈总统(LastVote,这个信息主要是保证总统的信息是完整的,它可能离线了一段时间缺失了一部分数据;另外也是告知总统自己在线),只要大多数结点在线,总统就通知大家写数据(Success)。只要大多数结点在线,写请求就会被通过,大多数结点在线才写数据是保证一致性的关键(个人观点)。对于那些暂时离线的结点,需要增加一些机制在它们重新加入集群时做replication。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: