zoukankan      html  css  js  c++  java
  • Zookeeper 介绍 原理

    简介:

             ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。
           它Google的Chubby一个开源的实现,在分布式协调技术方面做得比较好的就是Google的Chubby还有Apache的ZooKeeper
    他们都是分布式锁的实现者。
            有人会问 既然有了Chubby为什么还要弄一个ZooKeeper,难道Chubby做得不够好吗?不是这样的,主要是Chbby是非开源的,Google自家 用。
    后来雅虎模仿Chubby开发出了ZooKeeper,也实现了类似的分布式锁的功能,并且将ZooKeeper作为一种开源的程序捐献给了 Apache
            Zookeeper在分布式领域久经考验,它的可靠性,可用性都是经过理论和实践的验证的。所以我们 在构建一些分布式系统的时候,就可以以这类系统为起点来构建我们的系统,这将节省不少成本,而且bug也 将更少。

           Zookeeper是Hadoop和Hbase的重要组件。Zookeeper 分布式服务框架是Apache Hadoop 的一个子项目,
    它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
       

            ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务
    由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:
    配置维护、组服务、分布式消息队列分布式通知/协调等。

    角色

    Zookeeper中的角色主要有以下三类,如下表所示:

                             zookeeper简介

    系统模型如图所示:

                             zookeeper简介        

     设计目的

    1.最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。

    2 .可靠性:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。

    3 .实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。
        但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,
         如果需要最新数据,应该在读数据之前调用sync()接口。

    4 .等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。

    5.原子性:更新只能成功或者失败,没有中间状态。

    6 .顺序性:包括全局有序和偏序两种:
         全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;
         偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

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

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

    每个Server在工作过程中有三种状态:

    • LOOKING:当前Server不知道leader是谁,正在搜寻
    • LEADING:当前Server即为选举出来的leader
    • FOLLOWING:leader已经选举出来,当前Server与之同步


    选主流程

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

    同步流程

    选完leader以后,zk就进入状态同步过程。

            1. leader等待server连接;

            2 .Follower连接leader,将最大的zxid发送给leader;

            3 .Leader根据follower的zxid确定同步点;

            4 .完成同步后通知follower 已经成为uptodate状态;

            5 .Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。

    Leader工作流程

    Leader主要有三个功能:

            1 .恢复数据;

            2 .维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;

            3 .Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。

            PING消息是指Learner的心跳信息;
            REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;
            ACK消息是 Follower的对提议的回复,超过半数的Follower通过,则commit该提议; 
            REVALIDATE消息是用来延长SESSION有效时间。
            Leader的工作启动了三个线程来实现功能。

    Follower工作流程

    Follower主要有四个功能:

            1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);

            2 .接收Leader消息并进行处理;

            3 .接收Client的请求,如果为写请求,发送给Leader进行投票

            4 .返回Client结果。

    Follower的消息循环处理如下几种来自Leader的消息:

            1 .PING消息: 心跳消息;

            2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;

            3 .COMMIT消息:服务器端最新一次提案的信息;

            4 .UPTODATE消息:表明同步完成;

            5 .REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;

            6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

           Follower的工作是通过5个线程来实现功能的。



    原理:

    ZooKeeper在实现这些服务时,首先它设计一种新的数据结构——Znode,
    然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。
    有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。
    那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的

    ZooKeeper数据模型Znode

    ZooKeeper拥有一个层次的命名空间,这个和标准的文件系统非常相似,如下图所示。

    从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,
    ZooKeeper树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:

    (1) 引用方式

    Zonde通过路径引用,如同Unix中的文件路径。路径必须是绝对的,必须是唯一的
    路径由Unicode字符串组成,并且有一些限制。
    字符串"/zookeeper"用以保存管理信息,比如关键配额信息。

    (2) Znode结构

    ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。
    既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。
    图中的每个节点称为一个Znode。 每个Znode由3部分组成:

     stat:此为状态信息, 描述该Znode的版本, 权限等信息

     data:与该Znode关联的数据

     children:该Znode下的子节点

    ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储
    相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。
    这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。
    ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但常规使用中应该远小于此值。

    (3) 数据访问

    ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。
    另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

    (4) 节点类型

    ZooKeeper中的节点有两种,分别为临时节点永久节点
    节点的类型在创建时即被确定,并且不能改变。

    ① 临时节点该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,当然可以也可以手动删除。
    虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点。

    ② 永久节点该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

    (5) 顺序节点

    当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数
    这个计数对于此节点的父节点来说是唯一的,
    它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。

    (6) 观察

    客户端可以在节点上设置watch,我们称之为监视器
    当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,
    因为watch只能被触发一次,这样可以减少网络流量。

     

    ZooKeeper中的时间

    ZooKeeper有多种记录时间的形式,其中包含以下几个主要属性:

    (1) Zxid

    致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。
    也就是说,每个对 节点的改变都将产生一个唯一的Zxid。
    如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。

    实际 上,ZooKeeper的每个节点维护者三个Zxid值,为别为:cZxid、mZxid、pZxid

     cZxid: 是节点的创建时间所对应的Zxid格式时间戳。
    ② mZxid:是节点的修改时间所对应的Zxid格式时间戳。

    实际中Zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个 新的epoch。
    低32位是个递增计数

     (2) 版本号

    对节点的每一个操作都将致使这个节点的版本号增加。每个节点维护着三个版本号,他们分别为:

    ① version:节点数据版本号
    ② cversion:子节点版本号
    ③ aversion:节点所拥有的ACL版本号

    4.3 ZooKeeper节点属性

    通过前面的介绍,我们可以了解到,一个节点自身拥有表示其状态的许多重要属性,如下图所示。

    图 4.2 Znode节点属性结构


    ZooKeeper服务中操作

    在ZooKeeper中有9个基本操作,如下图所示:

    图 5.1 ZooKeeper类方法描述

    更新ZooKeeper操作是有限制的。
    delete或setData必须明确要更新的Znode的版本号,我们可以调用exists找到。
    如果版本号不匹配,更新将会失败。

    更新ZooKeeper操作是非阻塞式的。
    因此客户端如果失去了一个更新(由于另一个进程在同时更新这个Znode),
    他可以在不阻塞其他进程执行的情况下,选择重新尝试或进行其他操作。

    尽管ZooKeeper可以被看做是一个文件系统,但是处于便利,摒弃了一些文件系统地操作原语。
    因为文件非常的小并且使整体读写的,所以不需要打开、关闭或是寻地的操作。

    Watch触发器

    (1) watch概述

    ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()、getChildren()及getData()。
    watch事件是一次性的触发器,当watch的对象状态发生改变时,将会触发此对象上watch所对应的事件。
    watch事件将被异步地发送给客户端,并且ZooKeeper为watch机制提供了有序的一致性保证
    理论上,客户端接收watch事件的时间要快于其看到watch对象状态变化的时间。

    (2) watch类型

    ZooKeeper所管理的watch可以分为两类:

     数据watch(data  watches):getDataexists负责设置数据watch
    ② 孩子watch(child watches):getChildren负责设置孩子watch

    我们可以通过操作返回的数据来设置不同的watch:

    ① getData和exists:返回关于节点的数据信息
    ② getChildren:返回孩子列表

    因此

    ① 一个成功的setData操作将触发Znode的数据watch

     一个成功的create操作将触发Znode的数据watch以及孩子watch

    ③ 一个成功的delete操作将触发Znode的数据watch以及孩子watch

    (3) watch注册与处触发

    图 6.1 watch设置操作及相应的触发器如图下图所示:

    ① exists操作上的watch,在被监视的Znode创建删除数据更新时被触发。
     getData操作上的watch,在被监视的Znode删除数据更新时被触发。在被创建时不能被触发,因为只有Znode一定存在,getData操作才会成功。
     getChildren操作上的watch,在被监视的Znode的子节点创建删除,或是这个Znode自身被删除时被触发。可以通过查看watch事件类型来区分是Znode,还是他的子节点被删除:NodeDelete表示Znode被删除,NodeDeletedChanged表示子节点被删除。

    Watch由客户端所连接的ZooKeeper服务器在本地维护,因此watch可以非常容易地设置、管理和分派。当客户端连接到一个新的服务器 时,任何的会话事件都将可能触发watch。另外,当从服务器断开连接的时候,watch将不会被接收。但是,当一个客户端重新建立连接的时候,任何先前 注册过的watch都会被重新注册。

    (4) 需要注意的几点

    Zookeeper的watch实际上要处理两类事件:

    ① 连接状态事件(type=None, path=null)

    这类事件不需要注册,也不需要我们连续触发,我们只要处理就行了。

    ② 节点事件

    节点的建立,删除,数据的修改。它是one time trigger,我们需要不停的注册触发,还可能发生事件丢失的情况。

    上面2类事件都在Watch中处理,也就是重载的process(Event event)

    节点事件的触发,通过函数exists,getData或getChildren来处理这类函数,有双重作用:

    ① 注册触发事件

    ② 函数本身的功能

    函数的本身的功能又可以用异步的回调函数来实现,重载processResult()过程中处理函数本身的的功能。

  • 相关阅读:
    写代码注意了,打死都不要用 User 这个单词
    图解 Java 垃圾回收机制,写得非常好!
    Spring的核心模块解析
    单点登录终极方案之 CAS 应用及原理
    重磅!!Redis 6.0.0 已发布,有史以来改变最大的版本
    linux中$与()的一点使用疑惑解释
    mysql 行锁一则
    mysql: you can't specify target table 问题解决
    mysql update中需要根据条件列更新写法update case
    mysql depended_query 优化案例一则
  • 原文地址:https://www.cnblogs.com/centos2017/p/8118963.html
Copyright © 2011-2022 走看看