Basic Paxos
总的来说,Basic Paxos分成5个角色,俩个阶段,分别是
角色:
1.Client
Client发送一个请求到分布式系统,比如请求一个文件
1.Proposer
Proposer接收客户端的请求,并且让Acceptors接受这个请求。当发送冲突时,担任协调者。
2.Acceptors
一组Acceptors组成法定人数(一群Acceptors),任何发送给Acceptors的消息都必须发送给法定人数,从Acceptors收到的任何消息都应该忽略,
除非从法定人数内的每个Acceptors都收到一份同样的消息。
3.Learner
Learner充当协议的复制者,一旦Client的请求被Acceptors通过,Learner就可以执行客户端的请求(执行请求,响应数据给Client),为了保证可用性,Learner可以动态添加。
上面三个角色,任何一个参与者都可以扮演任意角色,但是在一轮共识过程中,只能担任一个角色(在共识形成后Learner才有作用)。
4.Leader
Paxos需要一个Proposer充当Leader来管理过程。但是可能有多个Proposer相信自己是Leader,协议保证只选择其中的一个,如果有多个Leader,就会出现冲突更新。
Quorums
Quorums表示法定人数,任何俩组法定人数,必须至少有一个Acceptor是重复的,n/2+1。
Phase1
P1a:Prepare
prepare过程由Proposer提出一个prepare message,格式是{n},n表示这次议案的编号(n唯一,并且按照时间顺序全局递增)。
Proposer 把这个议案发给法定人数(一组Acceptors),如果Proposer不能和法定人数通讯,不能开始这个过程。
注意:prepare message 不能包含提案的值v
P1b:Promise
Acceptors一直在等待prepare message,如果Acceptors收到prepare message,必须检查prepare message里面的编号值 n。
1.如果编号值 n 大于以前收到的任意提案值,Acceptors必须响应promise消息,同样,也必须忽略往后收到编号小于n的消息,
以前 Accept 过提案,它给Proposer的响应中必须包含先前 Accept 的提案,形式可能是{m,v}(m为提案的编号,v是 Accept 的值)。
2.编号n小于等于以前收到过的提案编号,Acceptor可以忽略这个提案(假装没有收到),当然,一个更优的做法是响应一个拒绝信息,用于通知Proposer结束这次提案。
Phase2
P2a:Accept
如果Proposer 从法定人数中收到足够多的promise,它需要把值v放进提案。如果有任何一个Acceptors 先前 Accept 过提案,Acceptors 会把 Accept 的提案响应给 Proposer,
比如是 {m,v}。那么,Proposer必须(must语义)把 v 设置成收到 Promise 内最高提案的值,比如是 z。
如果所有法定人数 Acceptors 响应说先前没有收到过提案,Proposer 可以设置任意的值 x。
Proposer发送 Accept 消息给Acceptor,消息的格式为{n,v}(v是 Proposer 选择的值,n是先前 prepare 阶段的提案编号)。
所以,Acceptors收到的 Accept 消息要么是 { n,z},要么是 { n,x }。
Accept消息应该理解成 " 请求 "," 请接受这次提案"。
P2b:Accepted
法定人数 Acceptors 从Proposer那里收到 { n,v } 的 Accept 消息,当Acceptors 在 P1b 中没有承诺给任何编号大于n的提案时,Acceptors必须接受值 v。
Acceptors 一旦接受值 v,应该回复一个 Accepted 消息给Proposer 和各个 Learner。
要不然就是不接受值 v,此时它应该忽略这个请求。
注意:
Acceptor可以接受多个提案,在其他Proposer还不知道新决定的值,并且用一个更高的n做编号发起提案就会出现这个情况。在这种情况下,虽然Acceptors在以前已经接受了一个新值, 它仍然可以响应 promise 并且 accept 新值,这些Proposer可能会有不同的值,但是,Paxos协议保证Acceptors都会一致同意一个单一值(新值覆盖旧值)。
缺陷模型
在多个Proposer发出冲突的Prepare message或者Proposer没有收到法定人数响应(Promise和Accepted),在这些情形下,如果发起新的提案。必须使用一个更高的提案编号
没有任何失败情形下的Basic Paxos流程
在下图内,1 个Client,1个Proposer,3个Acceptors(法定人数是3),2个Learner,图中表示的是第一轮共识,并且中间没有任何错误发生。
Client Proposer Acceptor Learner | | | | | | | X-------->| | | | | | Request | X--------->|->|->| | | Prepare(1) | |<---------X--X--X | | Promise(1,{Va,Vb,Vc}) | X--------->|->|->| | | Accept!(1,V) | |<---------X--X--X------>|->| Accepted(1,V) |<---------------------------------X--X Response | | | | | | |
在这里,V 是 {Va,Vb,Vc}中的最后一个
Acceptor失败时的Basic Paxos流程
下图表示有一个Acceptors失败了,但是剩余的Acceptors总数仍然占大多数(总共是3个Acceptor,挂了一个,还有俩个Acceptor),所以,Basic Paxos仍然会成功。
Client Proposer Acceptor Learner | | | | | | | X-------->| | | | | | Request | X--------->|->|->| | | Prepare(1) | | | | ! | | !! FAIL !! | |<---------X--X | | Promise(1,{Va, Vb, null}) | X--------->|->| | | Accept!(1,V) | |<---------X--X--------->|->| Accepted(1,V) |<---------------------------------X--X Response | | | | | |
冗余的Learner失败时的Basic Paxos的流程
下图表示有一个Learner失败,但是Basic Paxos仍然会成功
Client Proposer Acceptor Learner | | | | | | | X-------->| | | | | | Request | X--------->|->|->| | | Prepare(1) | |<---------X--X--X | | Promise(1,{Va,Vb,Vc}) | X--------->|->|->| | | Accept!(1,V) | |<---------X--X--X------>|->| Accepted(1,V) | | | | | | ! !! FAIL !! |<---------------------------------X Response | | | | | |
Proposer 失败时的Basic Paxos流程
在下面这个图中,Proposer在提出一个值的过程中失败了, 在Acceptor的Accepted返回之前,并且Proposer发送了一个Accept给了法定人数中的某一个Acceptor。
同时,出现了一个新的Leader(某个Proposer,图中没有画出来),注意图中画了俩轮共识,从上往下
Client Proposer Acceptor Learner | | | | | | | X----->| | | | | | Request | X------------>|->|->| | | Prepare(1) | |<------------X--X--X | | Promise(1,{Va, Vb, Vc}) | | | | | | | | | | | | | | !! Leader fails during broadcast !! | X------------>| | | | | Accept!(1,V) | ! | | | | | | | | | | | | !! NEW LEADER !! | X--------->|->|->| | | Prepare(2) | |<---------X--X--X | | Promise(2,{V, null, null}) -------响应Promise带上先前的Accept的提案,注意后俩个是null。 | X--------->|->|->| | | Accept!(2,V) | |<---------X--X--X------>|->| Accepted(2,V) |<---------------------------------X--X Response | | | | | | |
多个Proposers冲突的Basic Paxos流程
多个Proposers都相信自己是leader的时候最复杂,比如,当前的leader挂了,待会又恢复了,但是其他的Proposers已经变成了新的leader。从错误中恢复的leader没有学习到最新情况,
准备开始一轮冲突的操作。如下图所示。有4轮的失败情形,这个情况可能会持续下去(图的最下方)
Client Leader Acceptor Learner | | | | | | | X----->| | | | | | Request | X------------>|->|->| | | Prepare(1) | |<------------X--X--X | | Promise(1,{null,null,null}) | ! | | | | | !! LEADER FAILS | | | | | | | !! NEW LEADER (knows last number was 1) | X--------->|->|->| | | Prepare(2) | |<---------X--X--X | | Promise(2,{null,null,null}) | | | | | | | | !! OLD LEADER recovers | | | | | | | | !! OLD LEADER tries 2, denied | X------------>|->|->| | | Prepare(2) | |<------------X--X--X | | Nack(2) | | | | | | | | !! OLD LEADER tries 3 | X------------>|->|->| | | Prepare(3) | |<------------X--X--X | | Promise(3,{null,null,null}) | | | | | | | | !! NEW LEADER proposes, denied | | X--------->|->|->| | | Accept!(2,Va) | | |<---------X--X--X | | Nack(3) | | | | | | | | !! NEW LEADER tries 4 | | X--------->|->|->| | | Prepare(4) | | |<---------X--X--X | | Promise(4,{null,null,null}) | | | | | | | | !! OLD LEADER proposes, denied | X------------>|->|->| | | Accept!(3,Vb) | |<------------X--X--X | | Nack(4) | | | | | | | | ... and so on ...
注意:
上面图中的描述和 Accepted 处的描述有点不同,在 Accepted 中的描述是,Acceptors可以忽略这个Accept请求,但是,在上图中,Acceptors回复了一个Nack,并且带上了最新的提案编号,
最坏的情况下,这个冲突会持续冲突下去,谁也不能提交成功