Zookeeper 的一致性,体现的是什么一致呢?
根据前面讲的 zab 协议的同步流程,在 zookeeper 集群内部的数据副本 同步,是基于过半提交的策略,意味着它是最终一致性。并不满足强一致 的要求。
其实正确来说,zookeeper 是一个顺序一致性模型。由于 zookeeper 设 计出来是提供分布式锁服务,那么意味着它本身需要实现顺序一致性 ( http://zookeeper.apache.org/doc/r3.5.5/zookeeperProgrammers.html#ch_zkGuarantees )
顺序一致性是在分布式环境中实现分布式锁的基本要求,比如当一个多个 程序来争抢锁,如果 clientA 获得锁以后,后续所有来争抢锁的程序看到 的锁的状态都应该是被 clientA 锁定了,而不是其他状态。
ClientA/B/C 假设只串行执行, clientA 更新 zookeeper 上的一个值 x。 ClientB 和 clientC 分别读取集群的不同副本,返回的 x 的值是不一样的。 clientC 的读取操作是发生在 clientB 之后,但是却读到了过期的值。很明 显,这是一种弱一致模型。如果用它来实现锁机制是有问题的。
顺序一致性提供了更强的一致性保证,我们来观察下面这个图,从时间轴 来看,B0 发生在 A0 之前,读取的值是 0,B2 发生在 A0 之后,读取到的 x 的值为 1.而读操作 B1/C0/C1 和写操作 A0 在时间轴上有重叠,因此他们 可能读到旧的值为 0,也可能读到新的值 1. 但是在强顺序一致性模型中, 如果 B1 得到的 x 的值为 1,那么 C1 看到的值也一定是 1。
需要注意的是:由于网络的延迟以及系统本身执行请求的不确定性,会导 致请求发起的早的客户端不一定会在服务端执行得早。最终以服务端执行 的结果为准。
简单来说:顺序一致性是针对单个操作,单个数据对象。属于 CAP 中 C 这个范畴。一个数据被更新后,能够立马被后续的读操作读到。
但是 zookeeper 的顺序一致性实现是缩水版的,在下面这个网页中,可 以看到官网对于一致性这块做了解释,zookeeper 不保证在每个实例中,两个不同的客户端具有相同的 zookeeper 数据视图,由于网络延迟等因素,一个客户端可能会在另外一 个客户端收到更改通知之前执行更新。
除此之外,zookeeper 基于 zxid 以及阻塞队列的方式来实现请求的顺序 一致性。如果一个 client 连接到一个最新的 follower 上,那么它 read 读 取到了最新的数据,然后 client 由于网络原因重新连接到 zookeeper 节 点,而这个时候连接到一个还没有完成数据同步的 follower 节点,那么这 一次读到的数据不久是旧的数据吗?实际上 zookeeper 处理了这种情况, client 会记录自己已经读取到的最大的 zxid,如果 client 重连到 server 发 现 client 的 zxid 比自己大。
zookeeper 官网还说它保证了“Single System Image”,其解释为“A client will see the same view of the service regardless of the server that it connects to.”。实际上看来这个解释还是有一点误导性的。其实由上面 zxid 的原理可以看出,它表达的意思是“client 只要连接过一次 zookeeper,就 不会有历史的倒退”。 apache/zookeeper#931