很多同学应该使用过 ZooKeeper,它是一个开源的分布式协调服务,比如你可以使用它进行配置管理、名字服务等等。在 ZooKeeper 中,数据是以节点的形式存储的。如果你要用 ZooKeeper 做配置管理,那么就需要在里面创建指定配置,假设创建节点"/geekbang"和"/geekbang/time",步骤如下:
[zk: localhost:2181(CONNECTED) 7] create /geekbang 123 Created /geekbang [zk: localhost:2181(CONNECTED) 8] create /geekbang/time 456 Created /geekbang/time
我们分别创建了配置"/geekbang" 和"/geekbang/time",对应的值分别为 123 和 456。那么在这里我提个问题:你觉得在 ZooKeeper 中,能用兰伯特的 Multi-Paxos 实现各节点数据的共识和一致吗?
当然不行。因为兰伯特的 Multi-Paxos,虽然能保证达成共识后的值不再改变,但它不管关心达成共识的值是什么,也无法保证各值(也就是操作)的顺序性。这是为什么呢?这个问题是 ZAB 协议着力解决的,也是理解 ZAB 协议的关键。
不过,虽然大家都在提 ZAB 协议,但是在我看来,ZAB 协议和 ZooKeeper 代码耦合在一起,也就是说,你是无法单独使用 ZAB 协议的,所以一般而言,只需要理解 ZAB 协议的架构和基础原理就可以了,不需要对代码和细节做太多的深究。所以,我会从 ZAB 协议的最核心设计目标(如何实现操作的顺序性)出发,带你了解它的基础原理。
为什么 Multi-Paxos 无法实现操作顺序性?
兰伯特的 Multi-Paxos 解决的是一系列值如何达成共识的问题,它关心的是,对于指定序号的位置,最多只有一个指令(Command)会被选定,但它不关心选定的是哪个指令,也就是说,它不关心指令的顺序性(也就是操作的顺序性)。
这么说可能比较抽象,为了方便你理解,我举个具体的例子演示一下(一个 3 节点的 Multi-Paxos 集群),为了演示方便,我们假设当前所有节点被选定的指令的最大序号为 100,也就是说,新提议的指令对应的序号将为 101。