你需要了解的zookeeper相关知识

什么是zookeeper?

一句话描述:zookeeper是一个开源的高可靠的分布式系统协调器

主要提供:配置管理,命名,分布式锁,组服务。这些服务如果在自己的分布式应用中实现和维护起来会有很大工作量。有了zookeeper,我们可以直接拿来用它的一致性,组管理,leader选举等功能,也可以在此基础上构建自己的应用。

基础知识

  • zookeeper提供的是分布式应用所需的分布式协同服务。它提供了一系列基本要件供分布式应用去构建自己的高级分布式服务。zookeeper被设计的容易对其进行编程,使用的是类似于目录树的一种数据模型。
  • 众所周知,构建正确的分布式协同服务很难,很容易产生竞态条件和死锁,zookeeper的目标就是将我们从构建自己的分布式应用的协同器中解放出来。

设计目标

  1. 简单。 zookeeper允许各分布式进程间通过共享一个类似于文件目录树结构的有层级的命名空间来实现彼此间的协同,该命名空间是有一系列注册数据点组成,称为znode。和文件系统很像,所不同的是,znodes是保存在内存中,使zookeeper可以保持高性能低延迟。
  2. zookeeper实现高性能,高可用性,严格的顺序访问,使它可以应用于大型分布式系统。
  3. 备份。zookeeper服务本身也是由多台server组成的整体。各台server互相知道彼此,他们在自己的内存中放了各server的状态,只要server集群中一半以上的服务可用,整个zookeeper服务就是可用的。
你需要了解的zookeeper相关知识

  1. client只会连到一台server,client和server间保持tcp连接,以发送请求,获取响应,发送心跳,得到watch事件,一旦tcp连接断掉,client会同另一台server建立tcp连接。
  2. 有序。ZooKeeper会在每一个更新上打上数字标记,以表示这个ZooKeeper事务的顺序。这样以后的操作可以根据这个标记实现更高级的抽象,如同步原语。
  3. 快速。尤其是在读操作占大多数的场景下。ZooKeeper的读写速度相差大约10:1。

数据模型

前面讲了,非常像文件模型。每一个node都以路径来唯一标识。

你需要了解的zookeeper相关知识

ZooKeeper的Node可以有子Node,也可以存储数据,存储的数据用来处理协同,主要有状态信息,配置,位置信息等,通常很小。一般将node称为znode。

znode存储的数据中有个版本号,一旦数据有更新,这个版本号会自增。client在此获取数据时,会得到新的版本号。

znode是有版本的(version),每个znode中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据,version号自动增加。

znode中数据的读写都是原子的。每个node都有访问控制列表acl来严格控制谁可以做什么。

还有一种临时node(ephemeral nodes),这个临时node的生存周期是创建它的session的生存周期,一旦这个session断掉,这个临时node就会被删除,这是很有用的一个特性,可以用来实现分布式锁。 注意EPHEMERAL(临时的)类型的目录节点不能有子节点目录。

状态更新和监视

client可以在znode上设置watch,当znode的状态变化时将触发watch。当client和server的连接断掉,client会收到本地提醒。这个是Zookeeper的核心特性,Zookeeper的很多功能都是基于这个特性实现的。

Zookeeper watch是一种监听通知机制。Zookeeper所有的读操作getData(), getChildren()和 exists()都可以设置监视(watch),监视事件可以理解为一次性的触发器,官方定义如下: a watch event is one-time trigger, sent to the client that set the watch, whichoccurs when the data for which the watch was set changes。Watch的三个关键点:

  • 一次性触发)One-time trigger

当设置监视的数据发生改变时,该监视事件会被发送到客户端,例如,如果客户端调用了getData("/znode1", true) 并且稍后 /znode1 节点上的数据发生了改变或者被删除了,客户端将会获取到 /znode1 发生变化的监视事件,而如果 /znode1 再一次发生了变化,除非客户端再次对/znode1 设置监视,否则客户端不会收到事件通知。

  • 发送至客户端)Sent to the client

Zookeeper客户端和服务端是通过 socket 进行通信的,由于网络存在故障,所以监视事件很有可能不会成功地到达客户端,监视事件是异步发送至监视者的,Zookeeper 本身提供了顺序保证(ordering guarantee):即客户端只有首先看到了监视事件后,才会感知到它所设置监视的znode发生了变化(a client will never see a change for which it has set a watch until it first sees the watch event)。网络延迟或者其他因素可能导致不同的客户端在不同的时刻感知某一监视事件,但是不同的客户端所看到的一切具有一致的顺序。

  • 被设置 watch 的数据)The data for which the watch was set

这意味着znode节点本身具有不同的改变方式。你也可以想象 Zookeeper 维护了两条监视链表:数据监视和子节点监视(data watches and child watches) getData() 和exists()设置数据监视,getChildren()设置子节点监视。或者你也可以想象 Zookeeper 设置的不同监视返回不同的数据,getData() 和 exists() 返回znode节点的相关信息,而getChildren() 返回子节点列表。因此,setData() 会触发设置在某一节点上所设置的数据监视(假定数据设置成功),而一次成功的create() 操作则会出发当前节点上所设置的数据监视以及父节点的子节点监视。一次成功的 delete操作将会触发当前节点的数据监视和子节点监视事件,同时也会触发该节点父节点的child watch。

Zookeeper 中的监视是轻量级的,因此容易设置、维护和分发。当客户端与 Zookeeper 服务器失去联系时,客户端并不会收到监视事件的通知,只有当客户端重新连接后,若在必要的情况下,以前注册的监视会重新被注册并触发,对于开发人员来说这通常是透明的。只有一种情况会导致监视事件的丢失,即:通过exists()设置了某个znode节点的监视,但是如果某个客户端在此znode节点被创建和删除的时间间隔内与zookeeper服务器失去了联系,该客户端即使稍后重新连接 zookeeper服务器后也得不到事件通知。

session

你需要了解的zookeeper相关知识

如果Client因为Timeout和Zookeeper Server失去连接,client处在CONNECTING状态,会自动尝试再去连接Server,如果在session有效期内再次成功连接到某个Server,则回到CONNECTED状态。

注意:如果因为网络状态不好,client和Server失去联系,client会停留在当前状态,会尝试主动再次连接Zookeeper Server。client不能宣称自己的session expired,session expired是由Zookeeper Server来决定的,client可以选择自己主动关闭session。

保证

  • 一致性。按照client发送请求的顺序执行。
  • 原子性。
  • 单系统视图。不管client连到哪台server,它看到的服务视图都是一致的。
  • 可靠性。
  • 实时性。

api

ZooKeeper的设计目标有一个是简单性,所以它提供的api也设计的很简单。

  • create。创建一个node
  • delete。
  • exists。判断在这个location是否存在node
  • get data。从node获取数据。
  • set data。向node写数据。
  • get children。获取该node的子列表。
  • sync。等待数据传播完成。

实现

你需要了解的zookeeper相关知识

上图为ZooKeeper服务的抽象组件。每个server都会有一份自己的组件。

replicated database是内存数据库,存放着整个service数据。也就是说每个server都有全部的信息。更新操作会记日志到硬盘中已备恢复。写操作是先序列化到硬盘中,再应用到内存数据库。

从上图可以看出,读操作是直接从该client连的server 执行。

写操作要通过一致性协议来执行。

所有的写操作都会被转发到leader,由leader进行转发。所以ZooKeeper的读能力比写强大很多。

信息转发这层称为messaging层,负责维持leader和同步follower与leader的信息。messaging层使用原子性的信息协议,messaging层是原子性的,所以他可以保证每一个本地的信息复制都是可靠地。当leader收到一个写请求,计算写请求提交时的系统状态,然后将其转为一个投票事务,再计算新的状态(后面详细讲解)。

原子化广播(atomic broadcast)保证了每一个进程按照相同的顺序投递同一个消息。


分享到:


相關文章: