basic paxos是我见过最难懂的算法,我最近一个月都在研究这个东西,自认有一些粗浅的心得,在这里写一下我对它的理解算法
为了下降理解难度,本文使用了大量的比喻,可能词不达意,见谅微信
basic paxos只为了解决一个问题:一个分布式系统如何就某个值(决议)达成一致。网络
先给出Wiki上对paxos的流程说明:架构
basic paxos分为两个阶段:分布式
prepare 阶段:spa
1a) proposer选择一个提案编号n并将prepare请求发送给acceptors中的一个多数派;get
1b) acceptor收到prepare消息后,若是提案的编号大于它已经回复的全部prepare消息,则acceptor将本身上次接受的提案回复给proposer,并承诺再也不回复小于n的提案;原理
accept 阶段:请求
2a) 当一个proposer收到了多数acceptors对prepare的回复后,就进入批准阶段。它要向回复prepare请求的acceptors发送accept请求,包括编号n和根据P2c决定的value(若是根据P2c没有已经接受的value,那么它能够自由决定value)。qq
2b) 在不违背本身向其余proposer的承诺的前提下,acceptor收到accept请求后即接受这个请求。
p2c:若是一个编号为n的提案具备value v,那么存在一个多数派,要么他们中全部人都没有接受(accept)编号小于n的任何提案,要么他们已经接受(accept)的全部编号小于n的提案中编号最大的那个提案具备value v。
固然,上面说的简直不像是人话。下面我会尝试用更容易理解的方式来描述这个算法。
在拍卖行里拍卖商品时,须要对某个商品竞价。
咱们使用basic paxos来限制竞价者(proposer)与记帐员(acceptor),但愿能在有限轮竞价以后,肯定某个商品的归属。
前提
1. 记帐员有一张纸,一只铅笔,一只钢笔和一块橡皮。铅笔写下的字迹能够被抹掉,钢笔写下的字迹不能被抹掉。
2. 竞价员能够给本身更名
3. 有一种特殊的机制,可让竞价者每次的报价都不相同并且递增
竞价过程分为两个阶段:
准备阶段:
1a) 竞价者选择报价n,并将报价n发给超过一半的记帐员
1b) 记帐员收到竞价者的报价n以后
if(发现这个报价大于他以前收到过的全部报价) {
if(记帐员已经用钢笔写下其余竞价者的报价) {
记帐员将以前用钢笔写下的报价和竞价者的名字返回
} else {
if(记帐员已经用铅笔写下其余竞价者的报价) {
记帐员用橡皮抹去上一次用铅笔写下的报价
}
用铅笔写下报价n
}
} else {
忽略
}
确认阶段:
2a) 竞价者收到了大多数记帐员的回复后,竞价者会查看收到的全部回复。
若是记帐员的回复中带有其余竞价者的名字以及他的报价,那么竞价者会选择其中报价最高的那个回复,而后将本身的名字改为这个回复中带有的名字。
竞价者会向这些记帐员发起确认请求,确认请求中含有本身的报价n和本身的名字(名字可能在上一行中被更新)
2b) 记帐员收到确认请求以后
if(纸上只有铅笔写的报价n && 纸上用铅笔写下的报价n == 确认请求里的n) {
记帐员确认这个请求,用钢笔将确认请求中竞价者的名字和报价n写在纸上
}
补充:若是竞价者没有收到多数派的返回,会提升本身的报价(不与其余竞价者的竞价重复)而后从新尝试竞价
前提:咱们有p1p2两个竞价者,和a1a2a3三个记帐员
场景1
a. p1提出竞价请求:(1)
b. a1a2a3所有收到,都用铅笔在纸上记下(1),并回复p1
c. p1收到a1a2a3的回复,而后向a1a2a3发起确认请求(1,p1)
d. a1a2a3确认,都用钢笔将(1,p1)写在纸上
总结
这是一次正常状况下的请求,a1a2a3最终都记录了相同的值。
实际上,在这个场景里,paxos已经退化成了两阶段提交协议。
场景2
a. p1提出竞价请求:(1)
b. a1a2收到,都用铅笔在纸上记下(1),并回复p1,a3网络中断没有收到请求
c. p1收到a1a2的回复,而后向a1a2发起确认请求(1,p1)
d. a1a2确认,用钢笔将(1,p1)写在纸上
总结
虽然有一台机失效,可是依然保证了多数派写入数据的一致性。
场景3
a. p1提出竞价请求:(1)
b. a1a2a3所有收到,都用铅笔在纸上记下(1),并回复p1
c. p2提出竞价请求:(2)
d. a1a2a3所有收到,因为p2开价更高,因而放弃p1的竞价请求,都用铅笔在纸上记下(2),并回复p2
e. p1收到步骤b中a1a2a3的回复,向a1a2a3发起确认请求(1,p1)
f. 因为a1a2a3的纸上记录的价格都是2,所以不会理睬p1的确认请求
g. p2收到步骤d中a1a2a3的回复,向a1a2a3发起确认请求(2,p2)
h. a1a2a3确认,用钢笔将(2,p2)写在纸上
总结
虽然有两次竞价请求,可是最终只对其中一次竞价请求作出了回应
场景4
a. p1提出竞价请求(1)
b. a1a2收到,都用铅笔在纸上记下(1),并回复p1。而a3没有收到
c. p2提出竞价请求:(2)
d. a2a3收到,a3直接用铅笔在纸上写下(2),a2已经在纸上用铅笔记下(1),可是因为p2开价更高,因而放弃p1的竞价请求,用铅笔在纸上记下(2),并回复p2
e. p1收到步骤b中的回复,向a1a2发起确认请求(1,p1)
f. a1先收到确认请求,用钢笔在纸上记下(1,p1)。a2后收到确认请求,因为a2纸上写的是(2),所以不作反应
g. p1未能达成多数派确认
h. p2收到步骤d中的回复,向a2a3发起确认请求(2,p2)
i. a2a3收到确认请求,用钢笔在纸上记下(2,p2)
j. p2达成多数派确认
总结
两次时序上有交叉的竞价请求,致使a1a2a3的最终结果不彻底一致,可是a2a3依然达成了多数派的一致性。
若是想要得到最终确认后的结果,不能只作单点读取(若是读到a1就不对了),须要作一次多数派读取才行。
场景5
a. p1提出竞价请求(1)
b. a1a2a3所有收到,都用铅笔在纸上记下(1),并回复p1
c. p2提出竞价请求:(2)
d. a1a2a3所有收到,因为p2开价更高,因而放弃p1的竞价请求,都用铅笔在纸上记下(2),并回复p2
e. p1收到步骤b中a1a2a3的回复,向a1a2a3发起确认请求(1,p1)
f. 因为a1a2a3的纸上记录的价格都是2,所以不会理睬p1的确认请求
g. p1提升价格,发起竞价请求(3)
h. a1a2a3所有收到,因为p1此次开价更高,因而放弃p2的竞价请求,都用铅笔在纸上记下(3),并回复p1
i. p2收到步骤d中a1a2a3的回复,向a1a2a3发起确认请求(2,p2)
j. 因为a1a2a3的纸上记录的价格都是3,所以不会理睬p2的确认请求
k. p2提升价格,发起竞价请求(4,p2)
。。。
总结
p1和p2不断发起时序上交叉的竞价请求,致使竞价请求不断被互相覆盖
没法造成统一的竞价结果
这个就是所谓的活锁(live lock)
场景6
a. p1提出竞价请求:(1)
b. a1a2收到,都用铅笔在纸上记下(1),并回复p1,a3没有收到请求
c. p1收到a1a2的回复,而后向a1a2发起确认请求(1, p1)
d. a1a2确认,用钢笔将(1,p1)写在纸上
e. p2提出竞价请求(2)
f. a2a3收到,a3直接将(2)用铅笔写在纸上,a2的纸上已经用钢笔写下了(1,p1),所以将此信息返回给p2
g. p2收到a2和a3的回复,发现a2的纸上已经用钢笔写下了(1,p1),所以p2将本身的名字更名为p1,而后向a2a3发起确认请求(2,p1)
h. a3纸上用铅笔写下了(2),与收到的确认请求里的价格相等,所以a3将确认请求(2,p1)用钢笔写在纸上
i. p1在a1a2a3上达成所有确认
总结
虽然p1只在a1和a2上完成多数派确认,可是后来的p2会将这个确认传递给其余的记帐员