• ZooKeeper


    一、ZooKeeper入门

      1.1 ZooKeeper 概述

      Zookeeper是一个基于观察者模式分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以单机模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。

      1.2 集群机制

      Zookeeper集群的角色: Leader 和 follower 

      只要集群中有半数以上节点存活,集群就能提供服务

      1.3 ZooKeeper 特性

       1.一个leader,多个follower组成的集群

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

       3、分布式读写,更新请求转发,由leader实施

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

       5、数据更新原子性,一次数据更新要么成功,要么失败

       6、实时性,在一定时间范围内,client能读到最新数据

      1.4 数据结构

       1.层次化的目录结构,命名符合常规文件系统规范(类似文件系统) 

        

       2.每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识 

          3.节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点)

      1.5 应用场景

        1.统一命名服务

        分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务。类似于域名与ip之间对应关系,域名容易记住。通过名称来获取资源或服务的地址,提供者等信息按照层次结构组织服务/应用名称可将服务名称以及地址信息写到Zookeeper上,客户端通过Zookeeper获取可用服务列表类

     

        

        2.统一配置管理

    分布式环境下,配置文件管理和同步是一个常见问题。一个集群中,所有节点的配置信息是一致的,比如Hadoop。对配置文件修改后,希望能够快速同步到各个节点上配置管理可交由Zookeeper实现。可将配置信息写入Zookeeper的一个znode上。各个节点监听这个znode。一旦znode中的数据被修改,zookeeper将通知各个节点。

        3.服务器动态上下线

        

        4.软负载均衡

      

        5.分布式通知协调

        分布式环境中,经常存在一个服务需要知道它所管理的子服务的状态。例如,NameNode须知道各DataNode的状态,JobTracker须知道各TaskTracker的状态。心跳检测机制和信息推送也是可通过Zookeeper实现。

        6.分布式锁

           Zookeeper是强一致的。多个客户端同时在Zookeeper上创建相同znode,只有一个创建成功。Zookeeper实现锁的独占性。多个客户端同时在Zookeeper上创建相同znode ,创建成功的那个客户端得到锁,其他客户端等待。Zookeeper 控制锁的时序。各个客户端在某个znode下创建临时znode (类型为CreateMode. EPHEMERAL _SEQUENTIAL),这样,该znode可掌握全局访问时序。

        7.分布式队列

      两种队列。当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型。(可通过分布式锁实现)

          

    二、ZooKeeper 安装配置

       2.1 环境结构

         必须具有jdk环境。一共三个节点(zk服务器集群规模不小于3个节点),要求服务器之间系统时间保持一致。

       2.2 上传zk并且解压

        进行解压: tar -zxvf zookeeper-3.4.6.tar.gz      重命名: mv zookeeper-3.4.6 zookeeper

       2.3  修改zookeeper环境变量 

    vi /etc/profile
    export JAVA_HOME=/opt/jdk1.8.0_71
    export ZOOKEEPER_HOME=/usr/local/zookeeper
    export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    export PATH=$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin:$PATH
    
    source /etc/profile

       2.4 修改zoo_sample.cfg 文件

    cd /usr/local/zookeeper/conf
    mv zoo_sample.cfg zoo.cfg
    修改conf: vi zoo.cfg 修改两处
    (1) dataDir=/usr/local/zookeeper/data(注意同时在zookeeper创建data目录)
    (2)最后面添加
    server.0=bhz:2888:3888
    server.1=hadoop1:2888:3888
    server.2=hadoop2:2888:3888

      2.5 创建服务器标识

        创建文件夹: mkdir data    创建文件myid并填写内容为0: vi

      2.6 复制zookeeper

        进行复制zookeeper目录到hadoop01和hadoop02  

        还有/etc/profile文件    

        把hadoop01、 hadoop02中的myid文件里的值修改为1和2   

        路径(vi /usr/local/zookeeper/data/myid)

       2.7 启动Zookeeper

         路径: /usr/local/zookeeper/bin

         执行: zkServer.sh start(注意三台都要启动)

         状态: zkServer.sh  status(在三个节点上检验model,一个leader,2个fllower)

       2.8 配置参数解读

         tickTime:心跳时间,为了确保连接存在的,以毫秒为单位,最小超时时间为两个心跳时间

        initLimit:多少个心跳时间内,允许其他server连接并初始化数据,如果ZooKeeper管理的数据较大,则应相应增大这个值

        clientPort:服务的监听端口

        dataDir:用于存放内存数据库快照的文件夹,同时用于集群的myid文件也存在这个文件夹里(注意:一个配置文件只能包含一个dataDir字样,即使它被注释掉了。)

        dataLogDir:用于单独设置transaction log的目录,transaction log分离可以避免和普通log还有快照的竞争

        syncLimit:多少个tickTime内,允许follower同步,如果follower落后太多,则会被丢弃。

           server.A=B:C:D:

          A是一个数字,表示这个是第几号服务器,B是这个服务器的ip地址
          C第一个端口用来集群成员的信息交换,表示的是这个服务器与集群中的Leader服务器交换信息的端口
          D是在leader挂掉时专门用来进行选举leader所用

    三、内部原理:

      3.1 选举机制(重点)

        半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。

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

       

       3.2 节点类型

        Znode有两种类型:

          短暂(ephemeral)(create -e /app1/test1 “test1” 客户端断开连接zk删除ephemeral类型节点) 
          持久(persistent) (create -s /app1/test2 “test2” 客户端断开连接zk不删除persistent类型节点)

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

          PERSISTENT 
          PERSISTENT_SEQUENTIAL(持久序列/test0000000019 ) 
          EPHEMERAL 
          EPHEMERAL_SEQUENTIAL

        创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护 

        在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序

         

      3.3 stat 结构体

          1.czxid-创建节点的事务zxid

         每次修改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子节点数量

      

    四、Zookeeper实战

      4.1 客户端命令行操作: 

    • 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
    • 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
    • 创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串
    • 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
    • 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
    • 删除文件: delete /zk 将刚才创建的 znode 删除
    • 退出客户端: quit
    • 帮助命令: help

      4.2 API操作

        1.导入依赖

     <dependency>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
          <version>3.4.6</version>
        </dependency>

        2.代码实现

     private static final String ZK_ADDRESS="0.0.0.0:2181";//多个节点用,隔开
        private static final Integer ZK_TIMEOUT=2000;
    
        private static final CountDownLatch COUNT_DOWN_LATCH=new CountDownLatch(1000000000);
        public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
            /**
             *创建zookeeper对象
             * 连接地址  超时时间  监控对象
             */
    
            ZooKeeper zooKeeper=new ZooKeeper(ZK_ADDRESS, ZK_TIMEOUT, new Watcher() {
                //连接方法
                @Override
                public void process(WatchedEvent watchedEvent) {
                    //
                    COUNT_DOWN_LATCH.countDown();
                    System.out.println("建立连接成功");
                }
            });
    
            //堵塞主线程
            COUNT_DOWN_LATCH.await();
    
            //创建节点
           /* zooKeeper.create("/zk01","value01".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);*/
    
            //修改节点
           /* zooKeeper.setData("/zk01","hehe".getBytes(),0);*/
    
            //获取节点
            /*byte[] data = zooKeeper.getData("/zk01", false, new Stat());
            System.out.println(new String(data,"utf-8"));*/
    
            //删除节点
         /*   zooKeeper.delete("/zk01",-1);*/
    
            //关闭连接
            zooKeeper.close();

     (未完,后面补充)

  • 相关阅读:
    将在线图片转换成base64踩坑记录及静态资源跨域及缓存的处理
    MySQL大表拆分多个表的方式(横向拆分和纵向拆分)及如何解决跨表查询效率问题
    electron-vue项目打包踩坑指南
    如何在npm上发布vue插件
    MVC之前的那点事儿系列(9):MVC如何在Pipeline中接管请求的?
    MVC之前的那点事儿系列(8):UrlRouting的理解
    MVC之前的那点事儿系列(7):WebActivator的实现原理详解
    MVC之前的那点事儿系列(6):动态注册HttpModule
    MVC之前的那点事儿系列(5):Http Pipeline详细分析(下)
    MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)
  • 原文地址:https://www.cnblogs.com/xiao-ran/p/11937130.html
Copyright © 2020-2023  润新知