Zookeeper简介

什么是Zookeeper?

ZooKeeper 是一种集中式服务,用于维护配置信息、命名、提供分布式同步和提供组服务,所有这些类型的服务都以分布式应用程序的某种形式使用。在官网上也表明着“Apache ZooKeeper致力于开发和维护实现高度可靠的分布式协调的开源服务器”,也就是高度可靠的提供分布式协调,解决分布式应用的一个应用。

Zookeeper设计目标

  • 简单的数据模型:Zookeeper 允许各分布式应用通过一个共享的命名空间相互联系,该命名空间类似于一个标准的文件系统:由若干注册了的数据节点构成,这些节点类似于文件和目录。
  • 高可靠:为了保证高可用,Zookeeper 可以是集群形态部署,这样只要集群中大部分机器是可用的,那么Zookeeper 本身仍然可用。
  • 顺序访问:对于来自客户端的每个更新请求,Zookeeper 都会分配一个全局唯一的递增编号,这个编号反应了所有事物操作的先后顺序,应用程序可以使用 Zookeeper 这个特性来实现更高层次的同步原语,这个编号也叫时间戳 -zxid。
  • 高性能:Zookeeper 是高性能的,在读多于写的应用程序中尤其的高性能,因为写会导致所有服务器同步状态。

Zookeeper集群角色

Zookeeper 中分为 Leader,Follower,Observer 三种角色。
Zookeeper简介_第1张图片

Leader

Zookeeper 集群中所有的机器通过一个 Leader 选举过程来选定一台 Leader 机器,Leader 既可以为客户端提供写服务又能提供读服务。它是 Zookeeper 集群工作机制的核心,事务请求的唯一调度者和处理者,保证集群事务请求处理的顺序性。

Follower

它是 Zookeeper 集群的跟随者,只提供读服务,转发事务请求给 Leader 服务器;参与 Leader 选举投票;参与事务请求的 proposal 投票。

Observer

它是一种新型的节点,和 Follower 一样只提供读服务,但是 Observer 不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,在不影响写性能的情况下提升集群的读性能。

而对于用户来说客户端可以连接到任意一台 Zookeeper 服务器。客户端维护这个 TCP 连接,通过这个连接,客户端可以发送请求、得到应答,得到监视事件以及发送心跳。如果这个连接断了,客户端可以连接到另一个 Zookeeper 服务器。而集群内所有 server 基于 Zab 协议进行通信,保证数据一致性。同时集群中每个 Follower 都和 Leader 通信,Follower 接收来自 Leader 的所有变化消息,保存在自己内存。

节点介绍

Zookeeper 名称空间中的每个节点都由路径标识,名称是由斜杠(/)分隔的路径元素序列。在 Zookeeper 中每个命名空间都被成为 Znode,每个 Znode 包含一个路径和与之相关的元数据以及在其下面的孩子列表。
每个 Znode 维护了一个属性结构,该结构包括:版本号、ACL 变更、时间戳。每次 Znode 数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。并且每个 Znode 都有一个 ACL,用来限制是否可以访问该 Znode。
在一个命名空间中,对 Znode 上存储的数据执行读和写请求操作都是原子的。

节点类型

ZooKeeper 中的数据节点也分为持久节点、临时节点和有序节点三种类型:

  1. 持久节点:这种节点也是在 ZooKeeper 最为常用的,几乎所有业务场景中都会包含持久节点的创建。之所以叫作持久节点是因为一旦将节点创建为持久节点,该数据节点会一直存储在 ZooKeeper 服务器上,即使创建该节点的客户端与服务端的会话关闭了,该节点依然不会被删除。如果我们想删除持久节点,就要显式调用 delete 函数进行删除操作。
  2. 临时节点:该节点的一个最重要的特性就是临时性。所谓临时性是指,如果将节点创建为临时节点,那么该节点数据不会一直存储在 ZooKeeper 服务器上。当创建该临时节点的客户端会话因超时或发生异常而关闭时,该节点也相应在 ZooKeeper 服务器上被删除。同样,我们可以像删除持久节点一样主动删除临时节点。
  3. 有序节点:有序节点并不算是一种单独种类的节点,而是在之前提到的持久节点和临时节点特性的基础上,增加了一个节点有序的性质。所谓节点有序是说在我们创建有序节点的时候,ZooKeeper 服务器会自动使用一个单调递增的数字作为后缀,追加到我们创建节点的后边。例如一个客户端创建了一个路径为 works/task- 的有序节点,那么 ZooKeeper 将会生成一个序号并追加到该节点的路径后,最后该节点的路径为 works/task-1。通过这种方式我们可以直观的查看到节点的创建顺序。

节点的状态结构

每一个节点都有一个自己的状态属性,记录了节点本身的一些信息,这些属性包括的内容如下:

  • cZxid:节点被创建时候的事务ID
  • mZxid:节点最后一次被修改时候的事务ID
  • pZxid:该节点的子节点最后一次被修改时的事务ID。子节点删除或添加才会影响pZxid
  • ctime:节点被创建的时间
  • mtime:节点被修改的世界
  • dataVersion:这个节点数据改变的次数
  • cversion:子节点被改变的次数
  • aclVersion:节点的ACL(访问控制列表被改变的次数)
  • ephemeralOwner:创建该临时节点的 session ID。如果是持久节点,设置为0
  • dataLength:数据内容长度
  • numChildren:当前节点子节点的个数

节点的权限控制

ZooKeeper 提供了 ACL 来控制 Znode 节点的访问,只有符合了 ACL 控制,才可以操作该节点,否则将无法操作。它利用一个三元组来定义客户端的访问权限,这个认证机制是可以配置的。
命令格式如:scheme:expression,perms

  • Schema 代表权限控制模式:World 任何人;Auth 不需要 ID;Digest 用户名和密码方式的认证;IP Address IP地址方式的认证。
  • perms 代表权限:CREATE:创建子节点; READ:获取子节点与自身节点的数据信息;WRITE:在Znode节点上写数据;DELETE:删除子节点;ADMIN:设置ACL权限。

ZooKeeper Session会话

Session 是指 Zookeeper 服务器与客户端会话。在 Zookeeper 中,一个客户端连接是指客户端和服务器之间的一个 TCP 长连接。客户端启动的时候,首先会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期就开始了。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够像 Zookeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watch 事件通知。
Session 的 sessionTimeout 可以设置客户端会话的超时事件。由于服务压力大,网络故障或者客户端主动断开连接等各种原因导致客户端连接断开时,只要在 sessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。
在为客户端创建会话之前,服务端首先会为每个客户端都分配一个 sissionID(64位),由于 sessionID 是 Zookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于 sessionID 的,因此,无论是哪台服务器为客户端分配的 sessionID,都需要保证全局唯一。

Watch机制

Watcher 事件监听器,是 Zookeeper 中一个很重要的特性。Zookeeper 允许用于在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,Zookeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是Zookeeper 实现分布式协调服务的重要特性。
有如下的 Watcher 事件类型可能出现:

  • NodeChildrenChanged::Znode 的子节点创建或删除的时候。
  • NodeCreated::新的 Znode 节点被创建的时候。
  • NodeDataChanged:Znode 节点的数据改变了的时候。
  • NodeDeleted::Znode 节点被删除的时候。
    在这里有个点,在父节点我们可以监听到子节点的变换,如果如果需要监听更细致的就需要把这个子节点当成父节点再添加监听事件。

Zookeeper特点

  • 顺序一致性:从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 Zookeeper 中去。
  • 原子性:更新操作要么成功,要么失败,没有第三种结果。
  • 单一系统映像:无论客户端连到哪一个 Zookeeper 服务器,其看到的服务器数据模型都是一致的。
  • 可靠性:一旦一次更改请求被应用,更改结果就会被持久化,直到被下一次更改覆盖。
  • 实时性:Zookeeper 保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。 但由于网络延时等原因,Zookeeper 不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用 sync() 接口。

Zookeeper的三种部署方式

  1. 独立部署模式,即部署在单台机器上的一个 Zookeeper 服务,适用于学习、了解 Zookeeper 基础功能。
  2. 伪分布模式,即部署在一台机器上的多个(原则上大于 3 个)Zookeeper 服务,虚拟分布式的 Zookeeper 集群,适用于学习、开发和测试,不适用生产环境。
  3. 全分布式模式(复制模式),即在多台机器上部署 Zookeeper 服务,真正的集群模式,适合于学习、开发和测试,可投入到生产环境中使用。

Zookeeper典型使用场景

参考了这里

  1. 集群管理
    节点监控:集群环境下,有很多节点,节点可能因为网络故障连接不上,可能因为机器故障无法工作,要求保证集群中的节点都能正常工作,就需要把异常的节点从集群中屏蔽掉,这时使用 Zookeeper 的短暂节点和 Watcher机制,可以很好的实现集群的管理。
    领导者选举:集群是多个节点(可把节点理解为机器)协同工作,这是需要一个把控全局的领导者节点来接收外部请求、任务派发等,那么,领导者节点如何产生?领导者节点出现故障怎么处理?领导者选举是 Zookeeper 最优秀的功能之一,如果当前领导者节点出现故障,Zookeeper 可在很短的时间内选举出新的领导者来接替故障领导者的工作。
  2. 配置管理
    实际应用中,配置使应用变得灵活,但是在分布式应用下,需要到每一台机上面修改配置,维护配置则复杂很多,基于这种场景,把配置放在 Zookeeper 的 Znode 中,分布式应用的机器到 Zookeeper 的 Znode 中读取配置应用到系统中即可。此外,利用 Zookeeper 的 Watcher 机制,如果配置发生改变,Zookeeper 通知各个机器配置信息已经被修改,各机器通过刷新来获取到最新的配置。
  3. 命名服务
    命名服务就是指通过指定的名字来获取资源或者服务的地址。zk会在自己的文件系统上(树结构的文件系统)创建一个以路径为名称的节点,它可以指向提供的服务的地址,远程对象等。分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。
  4. 分布式计数器
    在分布式环境下,获取唯一 ID,功能和 Redis 自增返回值一样,指定一个 ZooKeeper 数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现计数功能。
  5. 分布式协调通知
    说分布式协调通知就有点广了,上面所说的配置服务和集群管理就是用到了分布式协调通知,分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。利用 ZooKeeper 中特有的 Watcher 注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。
    利用 ZooKeeper 的心跳机制和临时节点特性,可以让不同的机器都在 ZooKeeper 的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时节点来判断对应的客户端机器是否存活。通过这种方式,检测系统和被检测系统之间并不需要直接相关联,而是通过zk上的某个节点进行关联,大大减少了系统耦合。
  6. 发布订阅
    发布/订阅模式是一对多的关系,多个订阅者对象同时监听某一主题对象,这个主题对象在自身状态发生变化时会通知所有的订阅者对象。使它们能自动的更新自己的状态。发布/订阅可以使得发布方和订阅方独立封装、独立改变。当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象需要改变时可以使用发布/订阅模式。发布/订阅模式在分布式系统中的典型应用有配置管理和服务发现、注册。
    配置管理是指如果集群中的机器拥有某些相同的配置并且这些配置信息需要动态的改变,我们可以使用发布/订阅模式把配置做统一集中管理,让这些机器格子各自订阅配置信息的改变,当配置发生改变时,这些机器就可以得到通知并更新为最新的配置。
    服务发现、注册是指对集群中的服务上下线做统一管理。每个工作服务器都可以作为数据的发布方向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息,当工作服务器的基本信息发生改变如上下线、服务器角色或服务范围变更,监控服务器可以得到通知并响应这些变化。
  7. 分布式锁
    每个客户端对某个方法加锁时,在zk上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁。
  8. 队列管理
    ZooKeeper 队列不太适合要求高性能的场合,可以考虑在数据量不大的情况下使用。毕竟引进一个消息中间件会增加系统的复杂性和运维的压力。当然了,首先已有项目中要使用zk。
    使用 ZooKeeper 实现先进先出队列就是在特定的目录下创建 PERSISTENT_EQUENTIAL(永久、序列化)节点,创建成功时 Watcher 通知等待的队列,队列删除序列号最小的节点用以消费。此场景下 ZooKeeper 的Znode 用于消息存储,Znode 存储的数据就是消息队列中的消息内容,SEQUENTIAL 序列号就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。

你可能感兴趣的:(Zookeeper简介)