最近几天一直在看分布式一致性算法,paxos已经成为这个领域的事实标准,所以肯定绕不过它。
那paxos到底是什么,是一个具体算法还是一个协议框架。个人认为应该是一个解决分布式一致性问题的框架,后期的大部分工作都是在这个框架思路上做的优化。既然是个框架那他的核心思路是什么呢,我们是否可以用数学的方式去描述它,把它转换成一个带约束的优化问题(来看待后续的优化方案)。
这个框架要解决什么问题:发生诸如机器宕机或网络异常(包括消息的延迟、丢失、重复、乱序,还有网络分区)等情况。Paxos算法需要解决的问题就是如何在一个可能发生上述异常的分布式系统中,快速且正确地在集群内部对某个数据的值达成一致,并且保证不论发生以上任何异常,都不会破坏整个系统的一致性
解决思路是什么:问题转化一下就是,是否可以设计一种联结机制,对每个成员制定标准通过多轮的消息通讯达到最后数据一致。转换成数学问题就是一个消息发起者向量 点乘 消息发起者和决策者联接矩阵 点乘 消息发起者判别标准矩阵 点乘 决策者和消息发起者联结矩阵 点乘 决策者判别标准矩阵 = 消息发起者向量(最终)最后得到的消息发起者向量应该满足value是一致的条件。
如何验证这个解法的完备性:
消息发起者和决策者联接矩阵 因为网络异常和宕机会引入随机噪声,等价于要加上delta联结矩阵
决策者和消息发起者联结矩阵 因为网络异常和宕机会引入随机噪声,等价于要加上delta联结矩阵
噪声的引入不会影响到最后结果能一致。
怎么优化:
优化的目标,达到一致性时间越短越好。影响一致性时间因素:
1.消息发起者和决策者联接矩阵、决策者和消息发起者联结矩阵越稀疏需要的通讯连接越少
2.消息发起者判别标准矩阵、决策者判别标准矩阵,标准规则越少需要判别时间越短
3.消息发起者向量到达一致,迭代的轮次越少花费时间越短
4.消息发起决策者回复的两个阶段是否可以压缩
具体算法讲解:
1、第一阶段 Prepare
P1a:Proposer 发送 Prepare
Proposer 生成全局唯一且递增的提案 ID(Proposalid,以高位时间戳 + 低位机器 IP 可以保证唯一性和递增性),向 Paxos 集群的所有机器发送 PrepareRequest,这里无需携带提案内容,只携带 Proposalid 即可。
P1b:Acceptor 应答 Prepare
Acceptor 收到 PrepareRequest 后,做出“两个承诺,一个应答”。
两个承诺:
-
第一,不再应答 Proposalid 小于等于(注意:这里是 <= )当前请求的 PrepareRequest;
-
第二,不再应答 Proposalid 小于(注意:这里是 < )当前请求的 AcceptRequest
一个应答:
-
返回自己已经 Accept 过的提案中 ProposalID 最大的那个提案的内容,如果没有则返回空值;
注意:这“两个承诺”中,蕴含两个要点:
就是应答当前请求前,也要按照“两个承诺”检查是否会违背之前处理 PrepareRequest 时做出的承诺;
-
应答前要在本地持久化当前 Propsalid。
2、第二阶段 Accept
P2a:Proposer 发送 Accept
“提案生成规则”:Proposer 收集到多数派应答的 PrepareResponse 后,从中选择proposalid最大的提案内容,作为要发起 Accept 的提案,如果这个提案为空值,则可以自己随意决定提案内容。然后携带上当前 Proposalid,向 Paxos 集群的所有机器发送 AccpetRequest。
P2b:Acceptor 应答 Accept
Accpetor 收到 AccpetRequest 后,检查不违背自己之前作出的“两个承诺”情况下,持久化当前 Proposalid 和提案内容。最后 Proposer 收集到多数派应答的 AcceptResponse 后,形成决议。
Proposer生成提案
为了满足P2b,这里有个比较重要的思想:Proposer生成提案之前,应该先去『学习』已经被选定或者可能被选定的value,然后以该value作为自己提出的提案的value。如果没有value被选定,Proposer才可以自己决定value的值。这样才能达成一致。这个学习的阶段是通过一个『Prepare请求』实现的。
于是我们得到了如下的提案生成算法:
-
Proposer选择一个新的提案编号N,然后向某个Acceptor集合(半数以上)发送请求,要求该集合中的每个Acceptor做出如下响应(response)。
(a) 向Proposer承诺保证不再接受任何编号小于N的提案。
(b) 如果Acceptor已经接受过提案,那么就向Proposer响应已经接受过的编号小于N的最大编号的提案。
我们将该请求称为编号为N的Prepare请求。
-
如果Proposer收到了半数以上的Acceptor的响应,那么它就可以生成编号为N,Value为V的提案[N,V]。这里的V是所有的响应中编号最大的提案的Value。如果所有的响应中都没有提案,那 么此时V就可以由Proposer自己选择。
生成提案后,Proposer将该提案发送给半数以上的Acceptor集合,并期望这些Acceptor能接受该提案。我们称该请求为Accept请求。(注意:此时接受Accept请求的Acceptor集合不一定是之前响应Prepare请求的Acceptor集合)
Acceptor接受提案
Acceptor可以忽略任何请求(包括Prepare请求和Accept请求)而不用担心破坏算法的安全性。因此,我们这里要讨论的是什么时候Acceptor可以响应一个请求。
我们对Acceptor接受提案给出如下约束:
P1a:一个Acceptor只要尚未响应过任何编号大于N的Prepare请求,那么他就可以接受这个编号为N的提案。
如果Acceptor收到一个编号为N的Prepare请求,在此之前它已经响应过编号大于N的Prepare请求。根据P1a,该Acceptor不可能接受编号为N的提案。因此,该Acceptor可以忽略编号为N的Prepare请求。当然,也可以回复一个error,让Proposer尽早知道自己的提案不会被接受。
因此,一个Acceptor只需记住:1. 已接受的编号最大的提案 2. 已响应的请求的最大编号。
例子分析
算法优化和验证部分后续不上来
优化算法:
Negative responses
Bypassing phase two
Multi-Paxos
Fast paxos