paxos算法简析

Paxos是Lamport大神在1990年提出的,用来解决分布式系统一致性问题的算法。算法

分布式系统的一致性关注两个问题promise

1. 如何就某个决议达成一致性能优化

2. 如何在决议过程结束后保证能最终达成一致微信

 例如,在对某个变量达成一致的过程当中,会有多个关于这个变量的值的提议。一致性协议须要保证仅有一个被提议值被最终选择,且未选择这个值的节点可以学习到这个值,使集群最终关于这个值取得一致。异步

协议过程并不复杂,包括三类角色:Proposer(协议发起者)、Acceptor(协议接收者)、Learner(学习者)。具体流程以下分布式

1. Proposer广播prepare消息给Acceptor,包含提议序号n。若是Acceptor收到的prepare请求的n值比以前接收到的prepare请求的n值都大的话,回复promise消息表示不会再接受任何小于n的请求且带上以前accept的提议中编号小于n的最大的提议,不然不予理会。性能

2. Proposer接收到超过半数的Acceptor关于prepare消息(n)的承诺后,若是没有发现有一个Accepter接受过一个值,那么就向全部的Acceptor发送本身提议的值和序号n,不然,从全部接受过的值中选择一个提议编号最大的做为提议的值,提议编号仍为n。学习

3. Acceptor接受到提议后,若是该提议编号不违反本身作过的承诺的话,则接受该提议。Learner根据Acceptor的状态学习最终被肯定的值优化

注意:若是Proposer发出prepare(n)请求后,获得多数派的应答,而后能够再随便选择一个多数派广播accept请求,不必定要将accept请求发给有应答的Acceptor。ui

协议保证多数派达成一致后,不管采用学习的方法仍是重复前两步流程,最终都能就某个值达成一致。

 

Paxos流程并不复杂,可是证实过程比较复杂。Lamport为了让算法更容易被理解,在2001年写了Paxos Made Simple,这篇论文没有一个数学公式,采用逻辑推演的方法从新描述了算法的流程,但仍是没能显著下降算法理解的困难度。加之Paxos算法是纯理论的推导,工业实践过程当中每每会经历较大的改动,谷歌Chubby实现了基于Paxos的一致性算法,虽然做者确定了Paxos在一致性算法领域的地位,可是也认可工业落地后的Paxos算法和原始的Paxos算法差异很大。

 

国内开源的Paxos工业级别实现是微信的PhxPaxos类库。

具体实现设计:

Paxos是一个在异步通讯环境中,集群中多节点存活的条件下可以保证写入一致的协议。

Paxos只须要和集群中的多数accepter交互,便可完成一个值的肯定,一旦这个值被选定,不管proposer再发起任何值的写入,数据都不会再发生改变。

现有的大部分存储系统都经过AppendLog的形式肯定一个操做序列,当须要恢复一个存储时能够经过这个操做序列来恢复,而这个操做序列在肯定以后就永远不会被修改。

他们将Proposer、各个Acceptor、所服务的Data共同构成一个大集合,这个集合所运行的paxos算法最终目标是肯定一个值。咱们称这个集合为一个paxos实例。

实例只能肯定一个单独的值,如何完成多个实例的有序添加?

给每一个实例生成一个全局只增不减的编号ID,每一个机器的多个实例都是一个连续递增编号的有序系列,而基于Paxos协议的保证,同一个编号的实例在多一个机器上的值都是一致的,那么三台都得到了一个有序的多值存储。

然而因为可能出现宕机、消息丢失的状况,如何解决实例编号增加不一样步的问题?

Learner询问其余机器相同编号的实例,若是这个实例已经被销毁,则说明这个实例的值已经被肯定,直接将这个值写入当前实例中而后自增编号跳到下一个实例,如此反复,直到当前实例编号增加到和其它机器一致。

那么Paxos如何应用?

可重放的编辑日志和状态机结合

Paxos的每一个实例,就是状态转移的输入,因为每台机器的实例编号都是有序增加的,而每一个实例肯定的值是同样的,那么能够保证各台机器的状态输入是彻底一致的。根据状态机的理论,输入一致,那么引出的最终状态也是一致的。

一个Paxos工程实践的大体流程

客户端向Proposer发起请求,Proposer与实例编号相同的Acceptor协同工做肯定一个值,以后将这个值做为状态机的输入,产生状态转移,最终将状态转移结果返回给客户端。

 

实现中的性能优化:

严格落盘

Paxos协议的运做过程须要作出不少保证,即保证了在相同的条件下必定会作出相同的处理。磁盘是它记录下这些保证条目的介质。通常使用fsync来解决问题,也就是在每次进行写盘时都要附加一个fsync进行保证。

为保证Paxos的写盘性能,必需要尽量的减小Paxos算法所须要的写盘次数。理论上Paxos一次交互须要两次RTT,3次硬盘操做。PhxPaxos库将其减至一次RTT和一次硬盘操做,大大提升了Paxos协议的性能。

若是出现拜占庭问题的话,工程上就须要一系列的措施检测出这些拜占庭错误,而后选择性的进行数据回滚或直接丢弃。

一个Leader

多个Proposer写入是被容许的,只不过愈来愈多的Proposer进行同时写入,冲突的剧烈程度加大,虽然不会妨碍最终肯定一个值,但在性能上是比较差的。

一个Leader的引入不是为了解决一致性问题,而是为了解决性能问题。经过简单的心跳以及租约就能够作到。

状态机记录最大的实例编号

在每次启动时,将状态机告诉Paxos最大的实例编号x与Paxos发现本身最大的已肯定的实例编号y进行对比,若是有x<y的chosen value,咱们将这些value逐一输入到状态机,那么状态机的状态就会更新到y了,这个称为启动重放。

参考文章:

微信PaxosStore:深刻浅出Paxos算法协议 做者:郑建军

微信开源:生产级paxos类库PhxPaxos实现原理介绍 做者:lunncui

相关文章
相关标签/搜索