vlambda博客
学习文章列表

我看到的Paxos和ZAB(一)

 只是看书的一些记录,但是记录嘛,总带点拖沓,就拿来记忆而已。



Paxos为什么不适合ZooKeeper?


01



Paxos算法




在该算法中,三种角色参与,ProposerAcceptorLearner,仅仅关心角色之间的消息收发,而不关心进程的角色,因为不同时刻进程的角色会改变。(消息传输中假设消除了拜占庭式问题)


(省略一大堆提案选择的推导过程... )


以下是我觉得最关键的算法陈述,看完这几句话对于Paxos应该知道是怎么个逻辑了:

  • 阶段一:

    • Proposer选择一个提案号M<n>,然后向Acceptor的某个超过半数的子集成员发送编号为M<n>的Prepare请求。

    • 如果一个Acceptor收到一个编号为M<n>的Prepare请求,且编号M<n>大于该Acceptor已经响应的所有Prepare请求的编号,那么它就会将它已经批准过的最大编号的提案作为响应反馈给Proposer,同时该Acceptor会承诺不会再批准任何编号小于M<n>的提案。

    • 举个例子来说,假定Acceptor已经响应过的所有Prepare请求对应的提案编号分别为1、2、...、5、7,那么该Acceptor在接受到一个编号为8的Prepare请求后,会将编号为7的提案作为响应反馈给Proposer

  • 阶段二:

    • 如果Proposer收到来自半数以上的Acceptor对于其发出的编号为M<n>的Prepare请求的响应,那么它就会发送一个针对 [M<n>, V<n>] 提案的Accept请求给Acceptor。注意,V<n> 的值就是收到的响应中编号最大的提案的值(例如 V<n> V<7>),如果响应中不包含任何的提案,那么它就是任意值。

    • 如果Acceptor收到这个针对 [M<n>, V<n>] 提案的Accept请求,只要该Acceptor尚未对编号大于 M<n> 的Prepare请求作出响应,它就可以通过这个提案。

其实以上的过程很符合逻辑,就是作为Proposer,如果我在拟一个编号更大的提案,那么不接受旧的提案请求很正常;作为Acceptor,我已经收到过大编号的提案,那么我不接受过期的Prepare请求,并且告知Propeser,“你的提案过时了”。


对于提案的获取,有好几个方案,值得取舍:

  • 如果Acceptor直接将提案发送给Learner,那么就需要建立大量的连接进行通信,两者数量的乘积;

  • 设置一个主Learner,由其告知别的Learner,其实就是个Master,但是如果这个挂了怎么办;

  • 改进第二个方案,将提案消息发送给一群Learner,他们每一个都有Learner的责任来告知别的Learner,可靠性提高,但是网络复杂度提高。


书上有一个死循环的例子,同时也值得记录:

  • Proposer P1发送M<1>提案后,并且完成阶段一,Acceptor P2发送M<2>提案,且完成阶段二,那么Acceptor就会忽略提案编号小于2的提案,即当P1自信满满的发送Accept请求到Acceptor时惨遭拒绝,由此P1又发送一个M<3>,可想而知,P2的Accept请求也因此会被忽略,导致死循环。

导致的原因是因为两个都能发起提案的Proposer,因此只需要选取一个主的Proposer,即可保证算法的活性。


Paxos解决了什么问题,2PC、3PC不好吗?它们都很优秀,2PC解决了分布式事务的原子性问题,保证分布式事务的参与者要么都成功,要么都失败,但是存在同步阻塞、无限等待、脑裂问题;3PC通过添加一个PreCommit阶段来避免无限等待;而Paxos引入“过半”理念,解决无限等待,引入角色转换来解决一定程度上的单点问题和脑裂问题。



下回翻一下ZAB协议