zookeeper 是来自于google chubby。 为了解决在分布式环境下,如何从多个server中选举出master server。 那么这多个 server 就需要涉及到一致性问题,这个一致性体现的是多个 server 就 master 这个投票在分布式环境下达成一致性。简单来说就是最终听谁的。但是在网络环境中由于网络的不可靠性,会存在消息丢失和或者被篡改等问题。

所以,如何在这样一个环境中快速并且正确的在多个 server中对某一个数据达成一致性并且保证不论发生任何异常,都不会破坏整个系统一致性呢? 所以在Lamport大神设计了一套Paxos的算法,多个server基于这个算法就可以达成一致。而 google chubby 就是基于paxos算法的实现,用来实现分布式锁服务。并且提供了master选举的服务。

可能有的同学会有疑问,Chubby和paxos算法有什么关系?Chubby本来应该设计成一个包含Paxos算法的协议库,使得应用程序可以基于这个库方便的使用Paxos算法,但是它并没有这么做,而是把Chubby设计成了一个需要访问中心化节点的分布式锁服务。既然是一个服务,那么它肯定需要是一个高可靠的服务。所以Chubby被构建为一个集群,集群中存在一个中心节点(MASTER),采用Paxos协议,通过投票的方式来选举一个获得过半票数的服务器作为Master,在 chubby集群中,每个服务器都会维护一份数据的副本,在实际的运行过程中, 只有master服务器能执行事务操作,其他服务器都是使用paxos协议从master节点同步最新的数据。 而zookeeper是chubby的开源实现,所以实现原理和chubby基本是一致的。

1.一致性

一致性是分布式架构中最重要属性之一。

一致性:表示在分布式架构中,预期行为与实际行为的一致情况,以实现可预测。

一致性可以细分为数据一致性,读写一致性,选举一致性等,但一般简化成以下三类:

数据一致性指的是在leader更新数据后,follower必须保证数据与leader一致;而读写一致性指的是先读后写;还有选举一致性,指的是所有follower最后投票出来的leader必须一致。

  • 强一致性:数据a一旦写入成功,在任意副本任意时刻都能读到a的最新值。也称为原子一致性(Atomic Consistency)线性一致性(Linearizable Consistency。

  • 弱一致性:写入一个数据a成功后,在数据副本上可能读出来,也可能读不出来。不能保证多长时间之后每个副本的数据一定是一致的,其实就是不需要一致。

  • 结果一致性:写入一个数据a成功后,在其他副本有可能读不到a的最新值,但在某个时间窗口之后保证最终能读到。 可以看做弱一致性的一个特例,这里面的重点是这个时间窗口。

【Zookeeper】原理分析:zk到底是什么一致性?如何保证一致性?

注:一个多核CPU也可以认为是一个小型分布式系统,因此一致性也可用于单机

那 Zookeeper 的一致性体现的是什么一致呢?

2.zk的一致性策略

Zookeeper的一致性,体现的是什么一致呢? 根据前一篇【Zookeeper】原理分析:一致性保证–ZAB协议解析
讲的 zab 协议的同步流程,在 zookeeper 集群内部的数据副本同步,是基于过半提交的策略,意味着它是最终一致性。并不满足强一致的要求。

其实正确来说,zookeeper 是一个顺序一致性模型。由于 zookeeper 设 计出来是提供分布式锁服务,那么意味着它本身需要实现顺序一致性。顺序一致性是在分布式环境中实现分布式锁的基本要求,比如当一个多个程序来争抢锁,如果 clientA 获得锁以后,后续所有来争抢锁的程序看到的锁的状态都应该是被clientA 锁定了,而不是其他状态。

问题一:为什么不采用最终一致性?

先思考一个问题,假如说 zookeeper 是一个最终一致性模型,那么他会发生什么情况。

ClientA/B/C 假设只串行执行, ClientA 更新 zookeeper 上的一个值 x。 ClientB 和 ClientC 分别读取集群的不同副本,返回的 x 的值是不一样的。 ClientC的读取操作是发生在ClientB之后,但是却读到了过期的值。过程见下图:

【Zookeeper】原理分析:zk到底是什么一致性?如何保证一致性?
很明显,这是一种弱一致模型。如果用它来实现锁机制是有问题的。

问题二:什么是顺序一致性?

顺序一致性提供了更强的一致性保证,我们来观察下面这个图,

【Zookeeper】原理分析:zk到底是什么一致性?如何保证一致性?

从时间轴来看,B0发生在A0之前,读取的值是0,B2发生在A0之后,读取到的 x 的值为1.而读操作B1/C0/C1和写操作A0在时间轴上有重叠,因此他们可能读到旧的值为0,也可能读到新的值1. 但是在强顺序一致性模型中, 如果B1得到的x的值为1,那么C1看到的值也一定是1.

简单来说:顺序一致性是按照客户端的指令顺序,所有的进程以相同的顺序看到所有的修改。读操作未必能及时得到此前其他进程对同一数据的写更新。但是每个进程读到的该数据的不同值的顺序是一致的。

需要注意的是:由于网络的延迟以及系统本身执行请求的不确定性,会导致请求发起的早的客户端不一定会在服务端执行得早。最终以服务端执行的结果为准。

这里再放一个顺序一致性的参考链接

问题三:zk的顺序一致性是什么样子?

zookeeper 的顺序一致性实现其实是缩水版的,可以在官网看到对于一致性这块做了解释

【Zookeeper】原理分析:zk到底是什么一致性?如何保证一致性?

ZooKeeper不能保证每个实例在每个时间都有两个不同的客户端具有相同的ZooKeeper数据视图。由于诸如网络延迟之类的因素,一个客户端可能会在另一客户端收到更改通知之前执行更新。考虑两个客户端A和B的情况。如果客户端A将znode / a的值从0设置为1,然后告诉客户端B读取/ a,则客户端B可能读取旧值0,具体取决于哪个服务器。它连接到。如果客户端A和客户端B读取相同的值很重要,则客户端B应该调用sync()在执行读取之前,请使用ZooKeeper API方法中的方法。因此,ZooKeeper本身并不能保证所有服务器上的更改都会同步发生,但是ZooKeeper原语可用于构造更高级别的功能,以提供有用的客户端同步。

问题四:zk如何保证一致性?

ZooKeeper是一项高性能,可扩展的服务。读取和写入操作都被设计为快速,尽管读取比写入快。原因是在读取的情况下,ZooKeeper可以提供较旧的数据,而这又归因于ZooKeeper的一致性保证:

  • 顺序一致性:来自客户端的更新将按照发送的顺序应用。

    zookeeper 基于 zxid 以及阻塞队列的方式来实现请求的顺序一致性。

  • 原子性:更新操作的结果不是失败就是成功。即,如果更新操作失败,其他的客户端是不会知道的。

  • 系统视图唯一性:无论客户端连接到哪个服务器,都将看见唯一的系统视图。

    如果客户端在同一个会话中去连接一个新的服务器,那么他所看见的视图的状态不会比之前服务器上看见的更旧。当ensemble中的一个服务器宕机,客户端去尝试连接另外一台服务器时,如果这台服务器的状态旧于之前宕机的服务器,那么服务器将不会接受客户端的连接请求,直到服务器的状态赶上之前宕机的服务器为止。

    如果一个 client 连接到一个最新的 follower 上,那么它 read 读取到了最新的数据,然后 client 由于网络原因重新连接到 zookeeper 节点,而这个时候连接到一个还没有完成数据同步的follower节点,那么这一次读到的数据不久是旧的数据吗?实际上zookeeper处理了这种情况, client会记录自己已经读取到的最大的zxid,如果client重连到server发 现client的zxid比自己大,连接会失败。

  • 持久性:一旦更新操作成功,数据将被持久化到服务器上,并且不能撤销。所以服务器宕机重启,也不会影响数据。

  • 及时性:保证系统的客户视图在特定的时间范围内(约数十秒)是最新的。客户端将在此范围内看到系统更改,或者客户端将检测到服务中断。

    系统视图的状态更新的延迟时间是有一个上限的,最多不过几十秒。如果服务器的状态落后于其他服务器太多,ZooKeeper会宁可关闭这个服务器上的服务,强制客户端去连接一个状态更新的服务器。

使用这些一致性可以确保仅在ZooKeeper客户端上就可以轻松构建更高级别的功能,例如领导者选举,障碍,队列和读/写可撤销锁(无需对ZooKeeper进行任何添加)。

相关文章:

  • 2022-12-23
  • 2021-07-14
  • 2021-11-05
  • 2021-06-02
  • 2021-07-09
  • 2022-02-27
  • 2021-05-31
  • 2021-11-14
猜你喜欢
  • 2021-05-17
  • 2022-01-02
  • 2021-12-11
  • 2021-11-20
  • 2022-12-23
  • 2022-12-23
  • 2022-01-23
相关资源
相似解决方案