zoukankan      html  css  js  c++  java
  • Zookeeper简介

    1.概述

    1.1什么是zookeeper

      Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。
      Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应,从而实现集群中类似Master/Slave管理模式

      总结:     Zookeeper=文件系统(共享数据)+通知机制。

    (1)文件系统

       其实你简单的理解为zookeeper是一个类似于ztree的树形结构,每个节点都可以挂接数据,我们可以对这个目录树进行操作来满足我们的各种分布式需求。数据又可以自动按顺序排列等。

        

    (2)通知机制

      一个zk的节点可以被监控,包括这个目录中存储的数据的修改,子节点目录的变化,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的集中管理,集群管理,分布式锁等等。

           watch机制官方说明:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。

      

    1.2  ZooKeeper提供的常见服务如下 :

    • 命名服务 - 按名称标识集群中的节点。它类似于DNS,但仅对于节点。

    • 配置管理 - 加入节点的最近的和最新的系统配置信息。

    • 集群管理 - 实时地在集群和节点状态中加入/离开节点。

    • 选举算法 - 选举一个节点作为协调目的的leader。paxos算法

    • 锁定和同步服务 - 在修改数据的同时锁定数据。此机制可帮助你在连接其他分布式应用程序时进行自动故障恢复。

    • 高度可靠的数据注册表 - 即使在一个或几个节点关闭时也可以获得数据。

    1.3设计目标 

    1.简单的数据结构 简单的树形结构来进行相互协调,又称为树形名字空间

    2.可以构建集群    一般3-5台可以构成集群,而且集群中超过一半的机器正常工作就可以提供服务

    3.顺序访问    客户端的每一个请求,zookeeper都会生成一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序。应用程序可以使用这个特点来实现高层次的同步

    4.高性能    zookeeper将全量数据存在内存中,并直接服务于所有的非事务请求,因此在以读操作为主的场景中非常高效。

    2.应用场景

      提供的服务包括:分布式消息同步和协调机制、服务器节点动态上下线、统一配置管理、负载均衡、集群管理、分布式锁、分布式队列等。

    2.1 数据发布与订阅   集中式配置中心(推+拉),这个依赖于zookeeper节点可以存数据

    1.  应用启动时主动到Zookeeper上获取配置信息,并注册Watcher监听。
    2.  配置管理员变更Zookeeper配置节点的内容。
    3.  Zookeeper推送变更到应用,触发Watcher回调函数。
    4.  应用根据逻辑,主动获取新的配置信息,更改自身逻辑。

     2.2 软负载均衡

    1.  Register负责域名的注册,服务启动后将域名信息通过Register注册到Zookeeper相对应的域名服务下。
    2.  Dispatcher负责域名的解析。可以实现软负载均衡。
    3.  Scanner通过定时监测服务状态,动态更新节点地址信息。
    4.  Monitor负责收集服务信息与状态监控。
    5.  Controller提供后台Console,提供配置管理功能。

     

     2.3 集群管理

    • 有多少机器在工作?
    • 每台机器的运行状态收集
    • 对集群中设备进行上下线操作。
    • 分布式任务的状态汇报

      

    实现思路:也是借助于zookeeper的临时节点EPHEMERAL 。 

      Zookeeper 上创建一个 EPHEMERAL 类型的目录节点,然后每个 Server 在它们创建目录节点的父目录节点上调用 getChildren(String path, boolean watch) 方法并设置 watch 为 true,由于是 EPHEMERAL 目录节点,当创建它的 Server 死去,这个目录节点也随之被删除,所以 Children 将会变化,这时 getChildren上的 Watch 将会被调用,所以其它 Server 就知道已经有某台 Server 死去了。新增 Server 也是同样的原理。

    2.4 分布式锁

      当然分布式锁还可以用redis的setnx等实现。

       分布式锁,这个主要得益于ZooKeeper为我们保证了数据的强一致性。锁服务可以分为两类,一个是保持独占,另一个是控制时序

      保持独占,就是所有试图来获取这个锁的客户端,最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁,通过create znode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。(主要是利用zookeeper的临时节点,每个节点只在当前会话有效,断开连接之后节点就会自动消失。每次在执行之前都去get一下获取节点,如果获取不到就创建节点代表获取锁,并在结束之后删除节点;如果get可以获得就阻塞。如果两个线程同时get都为空都去create,只会有一个线程可以创建成功,第二个线程会抛出异常,因为zookeeper的创建节点都会交给leader操作,也就是不管多少线程同时去创建节点始终只有一个线程创建成功)

      控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执行,只是有个全局时序了。做法和上面基本类似,只是这里 /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERAL_SEQUENTIAL来指定)。Zk的父节点(/distribute_lock)维持一份sequence,保证子节点创建的时序性,从而也形成了每个客户端的全局时序。

    2.5分布式队列

      队列方面,简单地讲有两种,一种是常规的先进先出队列,另一种是要等到队列成员聚齐之后的才统一按序执行。

      对于第一种先进先出队列,和分布式锁服务中的控制时序场景基本原理一致。

      第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在 /queue 这个znode下预先建立一个/queue/num 节点,并且赋值为n(或者直接给/queue赋值n),表示队列大小,之后每次有队列成员加入后,就判断下是否已经到达队列大小,决定是否可以开始执行了。这种用法的典型场景是,分布式环境中,一个大任务Task A,需要在很多子任务完成(或条件就绪)情况下才能进行。这个时候,凡是其中一个子任务完成(就绪),那么就去 /taskList 下建立自己的临时时序节点(CreateMode.EPHEMERAL_SEQUENTIAL),当 /taskList 发现自己下面的子节点满足指定个数,就可以进行下一步按序进行处理了。

     3. zookeeper 简介

    3.0 架构

    部分描述
    Client(客户端)

    客户端,我们的分布式应用集群中的一个节点,从服务器访问信息。对于特定的时间间隔,每个客户端向服务器发送消息以使服务器知道客户端是活跃的。

    类似地,当客户端连接时,服务器发送确认码。如果连接的服务器没有响应,客户端会自动将消息重定向到另一个服务器。

    Server(服务器) 服务器,我们的ZooKeeper总体中的一个节点,为客户端提供所有的服务。向客户端发送确认码以告知服务器是活跃的。
    Ensemble ZooKeeper服务器组。形成ensemble所需的最小节点数为3。
    Leader 服务器节点,如果任何连接的节点失败,则执行自动恢复。Leader在服务启动时被选举。
    Follower 跟随leader指令的服务器节点。

     每个Server在工作过程中有三种状态: 
      LOOKING:当前Server不知道leader是谁,正在搜寻
      LEADING:当前Server即为选举出来的leader
      FOLLOWING:leader已经选举出来,当前Server与之同步

    3.1数据结构

      ZooKeeper数据模型的结构与Unix文件系统很类似(根节点是一个/),整体上可以看作是一棵树,每个节点称做一个ZNode。
      很显然zookeeper集群自身维护了一套数据结构。这个存储结构是一个树形结构,其上的每一个节点,我们称之为"znode",每一个znode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识。

    ZooKeeper数据模型中的每个znode都维护着一个 stat 结构。一个stat仅提供一个znode的元数据。它由版本号,操作控制列表(ACL),时间戳和数据长度组成。
      版本号 - 每个znode都有版本号,这意味着每当与znode相关联的数据发生变化时,其对应的版本号也会增加。当多个zookeeper客户端尝试在同一znode上执行操作时,版本号的使用就很重要。
      操作控制列表(ACL) - ACL基本上是访问znode的认证机制。它管理所有znode读取和写入操作。
      时间戳 - 时间戳表示创建和修改znode所经过的时间。它通常以毫秒为单位。ZooKeeper从“事务ID"(zxid)标识znode的每个更改。Zxid 是唯一的,并且为每个事务保留时间,以便你可以轻松地确定从一个请求到另一个请求所经过的时间。
      数据长度 - 存储在znode中的数据总量是数据长度。你最多可以存储1MB的数据。

     关于stat的更全的解释如下:

    1)czxid- 引起这个znode创建的zxid,创建节点的事务的zxid(ZooKeeper Transaction Id)
    每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。
    事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。
    2)ctime - znode被创建的毫秒数(从1970年开始)
    3)mzxid - znode最后更新的zxid
    4)mtime - znode最后修改的毫秒数(从1970年开始)
    5)pZxid-znode最后更新的子节点zxid
    6)cversion - znode子节点变化号,znode子节点修改次数
    7)dataversion - znode数据变化号
    8)aclVersion - znode访问控制列表的变化号
    9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
    10)dataLength- znode的数据长度
    11)numChildren - znode子节点数量

    3.2节点类型

    1. Znode有两种类型:

      短暂(ephemeral):客户端和服务器端断开连接后,创建的节点自己删除
      持久(persistent):客户端和服务器端断开连接后,创建的节点不删除

    2. Znode有四种形式的目录节点(默认是persistent )

    (1)持久化目录节点(PERSISTENT)
        客户端与zookeeper断开连接后,该节点依旧存在
    (2)持久化顺序编号目录节点(PERSISTENT_SEQUENTIAL)
        客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
    (3)临时目录节点(EPHEMERAL)
        客户端与zookeeper断开连接后,该节点被删除
    (4)临时顺序编号目录节点(EPHEMERAL_SEQUENTIAL)
        客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

    3.  创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
    4.  在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序

    3.3  特点

    1)Zookeeper:一个领导者(leader),多个跟随者(follower)组成的集群。

    2)Leader负责进行投票的发起和决议,更新系统状态

    3)Follower用于接收客户请求并向客户端返回结果,在选举Leader过程中参与投票

    4)集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。

    5)全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的。

    6)更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行。

    7)数据更新原子性,一次数据更新要么成功,要么失败。

    8)实时性,在一定时间范围内,client能读到最新数据。

    3.4选举机制

    1. 半数机制:集群中半数以上机器存活,集群可用。所以zookeeper适合装在奇数台机器上(也就是机器数量最好为2n+1)。

    2. Zookeeper虽然在配置文件中并没有指定master和slave。但是,zookeeper工作时,是有一个节点为leader,其他则为follower,Leader是通过内部的选举机制临时产生的

    3. 以一个简单的例子来说明整个选举的过程。

    假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么。

    (1)服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态。
    (2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
    (3)服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader。
    (4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
    (5)服务器5启动,同4一样当小弟。

      当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos

    3.5  Sessions(会话)

      会话对于ZooKeeper的操作非常重要。会话中的请求按FIFO顺序执行。一旦客户端连接到服务器,将建立会话并向客户端分配会话ID 。
      客户端以特定的时间间隔发送心跳以保持会话有效。如果ZooKeeper集合在超过服务器开启时指定的期间(会话超时)都没有从客户端接收到心跳,则它会判定客户端死机。
      会话超时通常以毫秒为单位。当会话由于任何原因结束时,在该会话期间创建的临时节点也会被删除。

    3.6 Watches(监视)

      监视是一种简单的机制,使客户端收到关于ZooKeeper集合中的更改的通知。客户端可以在读取特定znode时设置Watches。Watches会向注册的客户端发送任何znode(客户端注册表)更改的通知。
      Znode更改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。

      这个在之后学习了之后还会继续补充

    3.7   Zookeeper 角色与工作流

    (1)工作流

      一旦ZooKeeper集合启动,它将等待客户端连接。客户端将连接到ZooKeeper集合中的一个节点。一旦客户端被连接,节点将向特定客户端分配会话ID并向该客户端发送确认。如果客户端没有收到确认,它将尝试连接ZooKeeper集合中的另一个节点。 一旦连接到节点,客户端将以有规律的间隔向节点发送心跳,以确保连接不会丢失。

      在zookeeper中,客户端会随机连接到zookeeper集群中的一个节点,如果是读请求,就直接从当前节点中读取数据,如果是写请求,那么请求会被转发给leader提交事务,然后 leader会广播事务,只要有超过半数节点写入成功,那么写请求就会被提交

      所有事务请求必须由一个全局唯一的服务器来协调处理,这个服务器就是 Leader 服务器,其他的服务器就是follower。leader服务器把客户端的失去请求转化成一个事务 Proposal(提议),并把这个 Proposal 分发给集群中的所有 Follower 服务器。之后 Leader 服务器需要等待所有Follower服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈,那么 Leader 就会再次向所有的Follower服务器发送Commit消息,要求各个follower节点对前面的一个Proposal进行提交。

    (2)zookeeper的角色如下:

    • Leader角色

        Leader服务器是整个zookeeper集群的核心,主要的工作任务有两项 1. 事物请求的唯一调度和处理者,保证集群事物处理的顺 序性 2. 集群内部各服务器的调度者

    • Follower角色

      Follower角色的主要职责是 1. 处理客户端非事物请求、转发事物请求给leader服务器 2. 参与事物请求 Proposal 的投票(需要半数以上服务器 通过才能通知leader commit数据; Leader发起的提案, 要求Follower投票) 3. 参与Leader选举的投票

    • Observer角色

      Observer 是 zookeeper3.3 开始引入的一个全新的服务器 角色,从字面来理解,该角色充当了观察者的角色。 观察zookeeper集群中的最新状态变化并将这些状态变化 同步到 observer 服务器上。Observer 的工作原理与 follower 角色基本一致,而它和 follower 角色唯一的不同 在于 observer 不参与任何形式的投票,包括事物请求 Proposal的投票和leader选举的投票。简单来说,observer 服务器只提供非事物请求服务,通常在于不影响集群事物 处理能力的前提下提升集群非事物处理的能力

    3.8   zookeeper工作原理

      Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。 

      为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

      另一个重要的就是选举时候的paxos算法,当然这些只是在面试中问到,具体的了解就好。。。。。

  • 相关阅读:
    内存溢出与内存泄漏
    Android性能优化系列之Bitmap图片优化
    android 内存泄漏,以及检测方法
    android view绘制流程 面试
    USACO milking cows
    USACO beads
    POJ3311 TSP问题 xingxing在努力
    HDU5074 dp xingxing在努力
    HDU2821 深搜 xingxing1024
    HDU5592 排队问题 xingxing在努力
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10489290.html
Copyright © 2011-2022 走看看