zhihu 漫话分布式系统共识协议: Paxos篇
可能和很多人的印象相反, Paxos其实是一个异常简洁而精巧的算法. 解读一遍Paxos算法其实只需要5分钟. 本文将集中在经典的basic Paxos上, 而不会涉及其各种变种(实在也太多了).
前言
本文是“漫话分布式系统共识协议”这个系列的第二篇. 前一篇"2PC/3PC篇"介绍了分布式共识算法中最早的2PC和3PC两位老前辈.
再比因为Lamport稳重带皮的操作, 导致大家口口相传Paxos理解和实现起来有多困难多复杂, 导致出现了Raft这种改良版等等.
NOTE:
paxos和raft之间的关系
敲黑板: Paxos其实是一个异常简洁而精巧的算法. 解读一遍Paxos算法其实只需要5分钟. 真正复杂的地方在于想清楚Paxos算法在各种failure情形下如何依然"正确"的工作. 只有明白了这一层, 才算练成了Paxos的心法, 才能真正欣赏Paxos算法的精妙设计, 赞叹Lamport的天才思维. 在我看来, Paxos算法(连同Lamport的其他如BFT, Vector Clock等成就)是上个世纪八十/九十年代的经典分布式系统研究中最纯粹最优美, 也是整栋大厦底座最坚实的那一部分.
NOTE:
一、Leslie-Lamport
参见
Expert-Leslie-Lamport
章节二、BFT即Byzantine-Fault-Tolerance
插点题外话: 我第一次认真接触和学习Paxos是在CMU时TA分布式系统(15-440, Fall 2012: Distributed Systems).
Paxos算法描述
NOTE:
一、paper Paxos Made Simple
We let the three roles in the consensus algorithm be performed by three classes of agents: proposers, acceptors, and learners.
二、看了一下,下面的内容是使用 paper Paxos Made Simple 中的术语描述的
考虑一个简化了的Paxos系统: 只有leader和acceptor两种角色.
1、Prepare阶段
NOTE:
一、paper Paxos Made Simple
The algorithm chooses a leader, which plays the roles of the distinguished proposer and the distinguished learner.
二、Prepare阶段就是从proposer中选择一个作为leader,即leader election
(1a)
leader的节点给所有其他acceptor节点发送消息"proposal(n)"---n是该节点为这个提议选择的一个数字, 姑且理解为一个方案编号. 并期待该提议获得所有节点中的简单多数(Paxos的Quorum)的许可.
(1b)
每一个接受到proposal的acceptor节点:
一、如果这是它接受到的第一个proposal, 回答"promise". 代表该节点**许诺**将会保持承认该proposal发送方为leader, 除非收到其他优先级更高的proposal;
NOTE:
回答promise
二、如果已经有接收到并accepted(注: 这是下一阶段可能会发生的动作)其他的proposal(n',v')--n'是该proposal的方案号而v'是提议的共识:
1、如果 n < n', 之前accept的提议有更高优先级, 对新接受的提议回答"reject", 以兑现之前的许诺.
NOTE:
回答reject
2、如果 n > n', 回答"promise"的并同时附上旧的提议,proposal(n', v'). 这样在认可新的leader身份的同时, 也告诉了新的leader过去的被简单多数认可过的提议
NOTE:
回答promise
NOTE:
需要注意,上面仅仅列举了两种情况,其实不止两种情况,还有第三种情况,在 csdn 诸葛亮 VS 庞统,拿下 Paxos 共识算法 中,就列举了这种情况:
三、如果已经有接收到并promise其他的proposal(n',v')
1、如果 n < n',回答reject
2、如果 n > n',回答promise
(1c)
一、如果proposer的提议受到了简单多数的"reject", 竞争leader宣告失败, 可以放弃这一提议;
二、如果接受到了简单多数的"promise", 则该proposer成为leader, 它需要从收到的promise里附带的之前accepted的提议中选取方案号(n值)最高的对应的共识; 如果历史上没有被accept过的提议, leader可以自己选取一个共识v.
NOTE:
需要注意,它需要首先处理"之前accepted的提议中选取方案号(n值)最高的对应的共识"
2、Accept阶段
(2a)
leader会对所有acceptor发送"accept-request(n,v)", 请求所有acceptor接受编号为n的共识v的提议
(2b)
每一个接收到该提议的acceptor节点: 如果没有接受过编号比n更高的提议, 则返回"accept"表示接受这一共识提议; 否则返回"reject"
NOTE:
回答accept
回答reject
(2c)
如果简单多数的acceptor返回了"accept", 则共识达成; 否则共识失败, 重启Paxos协议.
请注意几点以帮助理解协议:
1、第一阶段竞争的并不是共识本身, 而是在争取坐实leader身份获得简单多数的认可
2、方案编号n本身并不是共识, 而是提议的一个优先级, 在多个节点竞争leader身份时可以区分优先顺序. 共识本身(v)会在下一阶段leader身份确认后由leader添加进提议;
NOTE:
显然"方案编号n"是为了处理多个节点同时竞争leader身份而添加的
3、虽然这一轮上只会有一个leader获得简单多数的认可产生, 但可能有多个"糊涂"节点认为自己应该做leader, 见后面的分析;
Paxos对2PC和3PC的改进
在我看来, Paxos对2PC和3PC有几点重要的改进.
第一,分离共识的提议者proposer以及帮助提议最终通过的leader这两个角色.
Paxos里, 即使一个leader身份被批准, 它也需要尊重历史上其他被同意过的提议. 换言之leader本身只是一个服务性的角色, 未必有机会自己提出共识.
NOTE:
这是一个非常深刻的认识
回忆一下上一篇介绍的2PC和3PC这两个协议当中, coordinator不仅负责提出最后的共识协议, 同时也负责服务所有节点保证它的共识被通过. 而正是因为Paxos中把coordinator的职责解耦合成了proposer和leader, 使得整个算法更加robust.就算前任leader宕机了, 后面新产生leader也可以继承前任的"遗志"来完成一个Paxos协议.
第二,对简单多数的巧妙应用.
第一阶段里选举leader要求的简单多数保证了选举出来的leader一定不会错过之前被accept过的提议---所以就算那个提议最初的proposer挂了, 也会至少被一个acceptor发给新的leader来继承. 而第二阶段里要求的达成共识的简单多数保证了有多个"自以为是"的leader出现时(比如一个leader掉线, 新leader选出, 旧leader重新上线), 一定只会有一个最后通过. 看过一个精彩的评论, 说Paxos其实就是连续运用两次"抽屉原理", 其实非常准确.
NOTE:
一、关于"Paxos其实就是连续运用两次"抽屉原理"",在下面的文章中有非常好的介绍:
1、cnblogs 分布式一致性算法——Paxos原理分析
我们称上面的算法为“多数同意算法”。为什么这个算法能够确保达成共识——换个说法,能够保证最多只有一个节点有权进行广播呢?用反证法很容易证明这一点。假设有两个提案者都收到了一半以上的接受回复,那么根据**抽屉原理**,回复这两个节点的接受者里面,必定会至少有一个节点同时回复了这两个提案者。这就产生了明显的矛盾——说好的只回复一个提案者呢?到此,我们已经保证了这个算法的正确性,任务似乎已经完成了。
Paxos与2PC/3PC的关系
Paxos如何克服2PC的问题
2PC的问题在于不能处理最简单的fail-stop错误模式.
1、2PC中coordinator是唯一而固定的, 如果coordinator宕机, 那么就会有情形导致coordinator之前propose的提议的投票结果丢失. 就算启动新的后备coordinator, 没有机制可以学习以前的投票结果.
2、Paxos因为分离了提议和leader, 从算法上保证总可以选举出后备leader并接替前任leader的工作.
Paxos如何克服3PC的问题
3PC改进了2PC的fail-stop的问题, 但是不能处理fail-recover类型的错误.
1、3PC发生的问题在于当有多个"自认的leader"出现时, 并不能有效的解决coordinator之间的竞争---谁是真正的coordinator.
2、而Paxos通过Quorum的运用, 保证了多了个leader之间可以互相发现.
Paxos的局限性
就像2PC以及3PC一样, Paxos也有其局限性.
1 活锁问题.
Paxos理论上存在一个不能终结协议的活锁竞争问题. 比如一个proposer提交的提议因为编号过低被拒绝时, 此proposer可能重启Paxos而提高编号重新提交. 如果同时有两个proposer都发现自己的方案编号过低, 从而轮流提出更高编号的proposal而导致对方被拒, 可能会导致死循环(或活锁).
NOTE:
不理解
2 恶意节点.
目前为止2PC, 3PC, Paxos均是假设所有节点都遵守协议的规定. 当存在恶意的, 可能发送任何导致协议停止或者出错的消息的节点存在时, 就需要有更强的共识算法在"守法节点"间达成共识. Lamport 的BFT(拜占庭将军问题)了解一下.