本文是个人总结的分布式系统技术的一个系列:分布式系统的复制技术/常见一致性算法及差异/分布式系统工程实践;这是“分布式系统的复制技术”的第三小节 --- Zab和Paxos间的差异。
联系作者:1120081006@qq.com
No, 尽管Zab和Paxos在很多方面类似,但Zab是一种和Paxos完全不同的协议,两者的相似之处包括:
Leader提议提案给Followers
Leader等待多数派Followers的ACK后,再确定一个提案的提交(被学习)
Zab中包含一个Epoch序号,和Paxos中的Ballot等价
从概念上讲,Zab和Paxos的主要区别是:Zab是为被动复制设计的,即主-备型系统(也成为Primary/Secondary或者Master/Slave等),比如Zookeeper;而不是为主动复制(复制状态机)设计的。
注意:
虽然主动复制和复制状态机不是一回事,但是大多数主动复制的系统,其复制的逻辑模型都是复制状态机。从这个角度我们把两者关联在一起,而不是把他们画等号。
主备复制和复制状态机之间的区别是什么呢?
为了更好地说明这个问题,我们把主-备复制简单地认为是“单主复制”,比如传统的MySQL复制,而复制状态机简单地认为是“多主复制”,比如Gelara和MySQL Group Replication。一个状态机是一个软件组件,它处理一系列的请求。每处理一个请求,状态机改变其内部状态并生成一个回应。一个状态机是确定性的定义是:如果两个状态机实例的初始状态一致,他们接收并处理相同的请求序列,最终两个状态机实例的状态是相同的,并且生成的回应也是相同的。
一个复制状态机系统是一个C/S型的系统,它保证系统中的每一个副本执行相同序列的客户端请求,即便这些请求是被多个客户端并发发起的,也不管这些请求达到各个副本的顺序。各个副本会通过一个分布式一致性算法就这些请求的执行顺序达成一致,例如Paxos算法。在同一时间并发发起的客户端请求可以以任何顺序执行,如果一个Leader故障,新的Leader在恢复的时候可以以任意顺序执行为提交的请求,因为这些请求尚未处理完成。
在类似Zookeeper的主-备系统中,备服务器就增量状态更新达成一致的应用顺序,这些增量状态更新由主服务器产生并发送给备服务器。和客户端请求不同,增量状态更新必须以其在主服务器上产生的严格顺序应用到备服务器。如果一个主服务器故障,新的主服务器不能按随意顺序应用这些未提交的增量状态更新,也不能从一个不同的初始状态开始应用增量状态更新。在MySQL的HA系统中,如果Master故障failover到某个Slave, 新Master还是必须按照旧Master上产生的Binlog来应用事务;当然,在正式对外提供服务之前,所有的MySQL实例必须达到一个一致状态。虽然目前实际应用中有很多HA逻辑并没有严格遵循这个规则,但其实这是非常危险的,HA逻辑必须保障已经处理了所有可能的异常或者异常永远不会发生,而这往往是大多数HA不可靠的根源。因为这是一种靠枚举已知的部分case来验证HA的正确性,而不是一种严谨的理论推导模型和数学方法,一旦出现了尚未预见的case,或者case中和你枚举的前提不一致,问题就出现了。
简而言之,主-备系统中要求就状态更新的执行顺序达成一致,而在复制状态机中要求就客户端请求的执行顺序达成一致。
一致性算法的含义是什么呢?
Paxos也可以用于主-备复制系统中,把主服务器当作Leader。Paxos的问题在于,如果主服务器在并发地处理多个状态更新的时候故障了,新的Leader可能以不同的顺序应用未提交的更新。在DSN 2011 paper中有一个针对这个问题的示例。在这个示例中,备服务器应该先应用A然后应用B。在例子中,使用Paxos后一个新主服务器和它的备服务器先应用C然后应用B,形成了一个旧主服务器达不到的错误的状态。(类似这样的故事,前两天在一次会议上一个同学非常自信的不以为然,他觉得他要在主从库之间多线程传输Binlog,要用多线程往Slave里面灌数据。我后面会专门写一篇文章来说明MySQL的复制中这个问题的重要性,不想表达别的,只想说明白问题!)
针对这个问题的一个变通方案是使用Paxos来串行地就状态更新达成一致:主服务器在上一个请求已经完成提交后在发起下一个提案。因为最多只有一个未提交的更新,新的主服务器不会产生错误的更新顺序。这个修复可以解决问题,但是性能却非常差!
Zab不需要这样的变通方案。Zab的备服务器可以并发地就多个状态更新顺序达成一致而不影响正确性。相比Paxos,Zab在恢复阶段加入了一个同步阶段,同步的原则是根据不同实例的zxids(详细说明见后续“Zab协议详解”)。




