ZooKeeper简介

1. 什么是 Zookeeper?

  • Zookeeper是一个高效的分布式协调服务,它暴露了一些公用服务,比如命名/配置管理/同步控制/群组服务等。我们可以使用ZK来实现比如达成共识/集群管理/leader选举等

  • Zookeeper 是一个高可用的分布式管理与协调框架,基于 ZAB 算法(原子消息广播协议)的实现。该框架能够很好地保证分布式环境中数据的一一致性。也正是基于这样的特性,使得 Zookeeper 成为了解决分布式一致性问题的利器。

    zookeeper五个特性

    • 顺序一致性:从一个客户端发起的事务请求,最终将会严格地按照其发起的顺序被应用到 zookeeper 中去。

    • 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群所有的机器都成功应用了某一事务,要么都没有应用,一定不会出现部分机器应用了该事务,而另一部分没有应用的情况。

    • 单一视图:无论客户端连接的是哪一个 zookeeper 服务器,其看到的服务器端数据模型都是一致的。

    • 可靠性:一旦服务器成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务器端状态将会被一致保留下来。除非有另外一个事务对其更改。

    • 实时性:通常所说的实时性就是指一旦事务被成功应用,那么客户端就能立刻从服务器上获取变更后的新数据,zookeeper 仅仅能保证在一段时间内,客户端最终一定能从服务幕端读敢最新的数据状态。

 

2. Zookeeper设计目标

  • 简单的数据结构:zookeeper 就是以简单的树形结构来进行相互协调的(也叫树形名字空间)。

  • 高可靠:一般 zookeeper 集群通常由一组机器构成,一般 3~5 台机器就可以组成一个 zookeeper 集群了。只要集群中超过半数以上的机器能够正常工作,那么整个集群就能够正常对外提供服务。

  • 有序访问:对于来自每一个客户端的每一个请求,zookeeper 都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序,应用程序可以使用 zookeeper 的这个特性来实现更高层次的同步。

  • 高性能:由于 zookeeper 将全量数据存储在内存中,并直接服务与所有的非事务请求,因此尤其是在读操作为主的场景下性能非常突出。在 JMater 压力测试下(100%读请求场景下),其结果大约在 12* ~13 W 的 QPS。

2.1 简单的数据模型

zk允许各分布式应用通过一个共享的命名空间相互联系,该命名空间类似于一个标准的文件系统:由若干注册了的数据节点构成(用zk的术语叫znode),这些节点类似于文件和目录。与专为存储而设计的典型文件系统不同,zk数据保存在内存中,这意味着zk可以实现高吞吐量和低延迟数量。

2.2 高可靠

就像zk需要协调的分布式系统一样,它本身就是具有冗余结构,它构建在一系列主机之上,构成zk服务的各服务器之间必须相互知道,它们维护着一个状态信息的内存映像,以及在持久化存储中维护着事务日志和快照。只要大部分服务器正常工作,zk服务就能正常工作。客户端连接到一台zk服务器。客户端维护这个TCP连接,通过这个连接,客户端可以发送请求、得到应答,得到监视事件以及发送心跳。如果这个连接断了,客户端可以连接到另一个zk服务器。

   1.客户端随机连接集群中任何一台server
   2.集群内所有server基于Zab(ZooKeeper Atomic Broadcast)协议进 行通信
   3.集群内部根据算法自动选举出一个leader,负责向follower(其他 server)广播所有变化消息
   4.集群中每个follower都和leader通信
         • Follower接收来自leader的所有变化消息,保存在自己内存
         • Follower转发来自客户端的写请求给leader
         • 客户端的读请求会在follower端直接服务,无需转发给leader

zk集群角色
Leader
①Leader服务器是zk集群工作机制的核心.
②事务请求的唯一调度者和处理者,保证集群事务请求处理的顺序性.
Follower
①Follower服务器是zk集群状态的跟随者.
②处理非事务请求,转发事务请求给Leader服务器
③参与事务请求的proposal投票
④参与Leader选举投票
Observer
Observer是一种新型的zk节点,Observer服务器只提供非事务服务.通常用于不影响集群事务处理能力的前提下提升集群的非事务的处理能力,Observer有另外一个优势,因为它不参与投票,所以他们不属于zk集群的关键部位,即使他们Failed,或者从集群中断开,也不会影响集群的可用性。

2.3 有序性

zk给每次更新附加一个数字标签,表明zk中的事务顺序,后续操作可以利用这个顺序来完成更高层次的抽象功能,例如同步原语操作。

2.4 高性能

zk特别适合于以读为主要负荷的场合。zk可以运行在数千台机器上,如果大部分操作为读,例如读写比例为10:1,zk的效率会很高

 

3.Zookeeper的数据模型

3.1 节点介绍

在zk中每个命名空间(Namespace)被称为znode,每个znode包含一个路径和与之相关的元数据,以及继承自该节点的孩子列表(临时节点下面不能创建子节点),zk旨在存储协调数据:状态信息,配置,位置信息等,因此存储在每个节点的数据通常很小,在字节到千字节范围内。

一个znode维护了一个属性结构,该结构包括:版本号、ACL变更、时间戳。每次znode数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。

每个znode都有一个ACL,用来限制是否可以访问该znode。

在一个命名空间中,对znode上存储的数据执行读和写请求操作都是原子的。

3.2 节点类型

注意:节点类型在节点创建的时候就被确定且不可改变

  • 临时节点(EPHEMERAL):临时创建的,会话结束节点自动被删除,也可以手动删除,临时节点不能拥有子节点.
  • 持久节点(PERSISTENT):创建后永久存在,除非主动删除。

以上两种节点为Non-sequence节点,只有一个可创建成功,其它匀失败。并且创建出的节点名称与创建时指定的节点名完全一样.

  • 临时顺序节点(EPHEMERAL_SEQUENTIAL):具有临时节点特征,但是它会有序列号。
  • 持久顺序节点(PERSISTENT_SEQUENTIAL):具有持久节点特征,但是它会有序列号。

以上两种节点为sequence节点,创建出的节点名在指定的名称之后带有10位10进制数的序号。多个客户端创建同一名称的节点时,都能创建成功,只是序号不同

容器节点(CONTAINER):如果节点中最后一个子Znode被删除,将会触发删除该Znode;
持久定时节点(PERSISTENT_WITH_TTL):客户端断开连接后不会自动删除Znode,如果该Znode没有子Znode且在给定TTL时间内无修改,该Znode将会被删除;TTL单位是毫秒,必须大于0且小于或等于 EphemeralType.MAX_TTL
持久顺序定时节点(PERSISTENT_SEQUENTIAL_WITH_TTL):同PERSISTENT_WITH_TTL,且Znode命名末尾自动添加递增编号;
以上三种节点是在3.5.3-beta版中才有的

3.3 节点信息

每一个Znode都有对应的stat结构,和文件系统类似。stat状态主要包含下面的信息:

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

3.4 节点的访问控制(ACL)

zk提供了ACL来控制znode节点的访问,只有符合了ACL控制,才可以操作该节点,否则将无法操作。
Zookeeper支持可配置的认证机制。它利用一个三元组来定义客户端的访问权限:
(scheme:expression, perms) 。其中:

Schema 代表权限控制模式,分别为:

  • World 任何人
  • Auth 不需要ID
  • Digest 用户名和密码方式的认证
  • IP Address IP地址方式的认证

perms(权限),ZooKeeper支持如下权限

  • CREATE: 创建子节点
  • READ: 获取子节点与自身节点的数据信息
  • WRITE:在Znode节点上写数据
  • DELETE:删除子节点
  • ADMIN:设置ACL权限

注意:
Znode的Acl只是针对某个节点,不会作用到它的子节点上
任何连接到ZooKeeper的客户端都可以使用exist操作,exist是不需要权限的。

 

4.Zookeeper Watch机制 

zk支持监听, 客户端能够设置监听znode节点. 当znode节点变更时可能触发或者移除监听.当监听事件被触发了,客户端将会收到数据通知包,告诉客户端节点数据被修改了. 同时如果当前客户端和zk节点的连接被断开了.客户端将收到一个本地通知.

有如下的Watcher事件类型可能出现:

  • NodeChildrenChanged: zNode的子节点创建或删除的时候
  • NodeCreated: 新的Znode节点被创建的时候
  • NodeDataChanged: Znode节点的数据改变了的时候
  • NodeDeleted: Znode节点被删除的时候。

Watcher操作特点

  • 主动推送 Watch被触发时,由 zk 服务器主动将更新推送给客户端,而不需要客户端轮询。
  • 一次性 数据变化时,Watch 只会被触发一次。如果客户端想得到后续更新的通知,必须要在 Watch 被触发后重新注册一个 Watch。
  • 可见性 如果一个客户端在读请求中附带 Watch,Watch 被触发的同时再次读取数据,客户端在得到 Watch 消息之前肯定不可能看到更新后的数据。换句话说,更新通知先于更新结果。
  • 顺序性 如果多个更新触发了多个 Watch ,那 Watch 被触发的顺序与更新顺序一致。避免安装大量watches侦听在同一个节点
  • 无法保证跟踪到每一个变化

 

5.应用场景及对应的特性

配置管理服务

例如当当的configtoolkit配置中心,就是将配置信息放到了zk上,假如你有20个节点,需要修改配置文件的时候,你总不能一个节点一个节点去更改吧 那假如有100个节点呢?在分布式系统中,有很多实例中的大多数配置项是相同的(比如数据库连接等),需要改变配置项,如果有zk的话,不需要在每个实例去修改。所有实例在启动时,都回去zk拉取节点信息,当节点信息修改的时候会通知到每一个实例,某些配置项也可以达到热配置的效果。

集群管理(Master选举)

在分布式的集群中,经常会由于各种原因,比如硬件故障,软件故障,网络问题,有些节点会进进出出。有新的节点加入进来,也有老的节点退出集群。这个时候,集群中其他机器需要感知到这种变化,然后根据这种变化做出对应的决策。比如我们是一个分布式存储系统,有一个中央控制节点负责存储的分配,当有新的存储进来的时候我们要根据现在集群目前的状态来分配存储节点。这个时候我们就需要动态感知到集群目前的状态。还有,比如一个分布式的SOA架构中,服务是一个集群提供的,当消费者访问某个服务时,就需要采用某种机制发现现在有哪些节点可以提供该服务(这也称之为服务发现,比如Alibaba开源的SOA框架Dubbo就采用了zk作为服务发现的底层机制)。还有开源的Kafka队列就采用了zk作为Cosnumer的上下线管理。
还有一个场景:集群选master,一旦master挂掉能够马上能从slave中选出一个master,这个实现和上面实现一样。

命名服务

命名服务就是指通过指定的名字来获取资源或者服务的地址。zk会在自己的文件系统上(树结构的文件系统)创建一个以路径为名称的节点,它可以指向提供的服务的地址,远程对象等。分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务地址列表。

分布式计数器

在分布式环境下,获取唯一id,功能和redis自增返回值一样,指定一个Zookeeper数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现计数功能。

分布式协调通知

说分布式协调通知就有点广了,上面所说的配置服务和集群管理就是用到了分布式协调通知,分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。
利用zk中特有的Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与通知,从而实现对数据变更的实时处理。
利用zk的心跳机制和临时节点特性,可以让不同的机器都在zk的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时节点来判断对应的客户端机器是否存活。通过这种方式,检测系统和被检测系统之间并不需要直接相关联,而是通过zk上的某个节点进行关联,大大减少了系统耦合。

发布订阅

发布/订阅模式是一对多的关系,多个订阅者对象同时监听某一主题对象,这个主题对象在自身状态发生变化时会通知所有的订阅者对象。使它们能自动的更新自己的状态。发布/订阅可以使得发布方和订阅方独立封装、独立改变。当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象需要改变时可以使用发布/订阅模式。发布/订阅模式在分布式系统中的典型应用有配置管理和服务发现、注册。

配置管理是指如果集群中的机器拥有某些相同的配置并且这些配置信息需要动态的改变,我们可以使用发布/订阅模式把配置做统一集中管理,让这些机器格子各自订阅配置信息的改变,当配置发生改变时,这些机器就可以得到通知并更新为最新的配置。

服务发现、注册是指对集群中的服务上下线做统一管理。每个工作服务器都可以作为数据的发布方向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息,当工作服务器的基本信息发生改变如上下线、服务器角色或服务范围变更,监控服务器可以得到通知并响应这些变化。

分布式锁

每个客户端对某个方法加锁时,在zk上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁。

队列管理

zk队列不太适合要求高性能的场合,可以考虑在数据量不大的情况下使用。毕竟引进一个消息中间件会增加系统的复杂性和运维的压力。当然了,首先已有项目中要使用zk。
使用zk实现先进先出队列就是在特定的目录下创建PERSISTENT_EQUENTIAL(永久、序列化)节点,创建成功时Watcher通知等待的队列,队列删除序列号最小的节点用以消费。此场景下zk的znode用于消息存储,znode存储的数据就是消息队列中的消息内容,SEQUENTIAL序列号就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值