• zookeeper


    概念:一个分布式协调技术,高性能的,开源的分布式系统协调服务。

    zookeeper=类似unix文件系统+通知机制+Znode节点

    下载地址:https://zookeeper.apache.org/releases.html

    功能:

    1. 统一命名服务
    2. 配置管理
    3. Java操作API

    一、安装

    bin目录下

    启动:./zkServer.sh start

    暂停:./zkServer.sh stop

    客户端: ./zkCli.sh

    退出:quit

    注意:运行需要Java环境。

    1、helloWorld

    文件系统:所使用的数据模型风格很像文件系统的目录树结构,简单来说,有点类似windows中注册表的结构

    有名称,有树节点,有Key(键)/Value(值)对的关系。

    可以看做一个树形结构的数据库,分布在不同的机器上做名称管理。

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

    二、数据模型Znode节点深入

    1、znode的数据模型

    Znode维护了一个stat结构,这个stat包含数据变化的版本号、访问控制列表变化、还有时间戳。版本号和时间戳一起,可让Zookeeper验证缓存和协调更新。每次znode的数据发生了变化,版本号就增加。

    ZooKeeper的结构体

    1. czxid- 引起这个znode创建的zxid,创建节点的事务的zxid(ZooKeeper Transaction Id)
    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内部维护了一套类似UNIX的树形数据结构:由znode构成的集合,

    znode的集合又是一个树形结构,每一个znode又有很多属性进行描述。 Znode = path + data + Stat

    2、znode中的存在类型

    1. PERSISTENT-持久化目录节点 create 默认
    2. PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点 create -s
    3. EPHEMERAL-临时目录节点 create -e
    4. EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点 create -s -e

    PERSISTENT-持久化节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点也不会被删除

    PERSISTENT_SEQUENTIAL-持久化顺序编号节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当客户端与zookeeper服务的连接断开后,这个节点也不会被删除。

    EPHEMERAL-临时目录节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点(还有涉及到的子节点)就会被删除。

    EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当创建这个节点的客户端与zookeeper服务的连接断开后,这个节点被删除。

    三、基础命令和Java客户端操作

    1、zkCli的常用命令操作

    1. ls
    2. ls2 查看当前节点数据并能看到更新次数等数据
    3. stat 查看节点状态
    4. set
    5. get
    6. create 默认无参持久化 --s含有序列 -e临时 可以同时用
    7. delete 删除无子节点的目录
    8. rmr 递归删除

    2、四字命令

    概念:zookeeper支持某些特定的四字命令,他们大多是用来查询ZK服务的当前状态及相关信息的,
    通过telnet或nc向zookeeper提交相应命令,如:echo ruok | nc 127.0.0.1 2181

    常用命令:

    3、Java客户端操作

    1、导入JAR包

       <dependency>
         <groupId>com.101tec</groupId>
         <artifactId>zkclient</artifactId>
         <version>0.10</version>
       </dependency>
    
       <dependency>
         <groupId>org.apache.zookeeper</groupId>
         <artifactId>zookeeper</artifactId>
         <version>3.4.9</version>
       </dependency>
    

    2、log4j

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
        <appender name="log.console" class="org.apache.log4j.ConsoleAppender">
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %5p (%C{1}:%M) - %m%n"/>
            </layout>
            <!--
            <filter class="org.apache.log4j.varia.LevelRangeFilter">
               <param name="levelMin"   value="debug" />
               <param name="levelMax"   value="warn" />
               <param name="AcceptOnMatch" value="true" />
            </filter>-->
    
        </appender>
    
        <appender name="log.file" class="org.apache.log4j.DailyRollingFileAppender">
            <param name="File" value="D:\atguigu4XML.log"/>
            <param name="Append" value="true"/>
            <param name="DatePattern" value="'.'yyyy-MM-dd"/>
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %5p (%C{1}:%M) - %m%n"/>
            </layout>
            <!-- <filter class="org.apache.log4j.varia.LevelRangeFilter">
               <param name="levelMin"   value="info" />
               <param name="levelMax"   value="info" />
               <param name="AcceptOnMatch" value="true" />
              </filter> -->
        </appender>
        <!--
        <logger name="com.atguigu" >
         <level value="info" />
         <appender-ref ref="log.console" />
         <appender-ref ref="log.file" />
        </logger>
    
        <logger name="com.atguigu.dao" >
         <level value="debug" />
         <appender-ref ref="log.console" />
         <appender-ref ref="log.file" />
        </logger>-->
    
        <!-- -->
        <root>
            <level value="info"/>
            <appender-ref ref="log.console"/>
            <appender-ref ref="log.file"/>
        </root>
    </log4j:configuration>
    
    
    

    3、java代码API操作zookeeper

    import org.apache.zookeeper.*;
    import org.apache.zookeeper.data.Stat;
    
    import java.io.IOException;
    
    /**
     * @Description:
     * @Auther: Tang
     * @Date: 2020/9/27 0027 下午 20:45
     */
    public class WatchMore {
    
        private static final String CONNECTSTRING = "39.99.144.224:2181";
        private static final String PATH = "/tang";
        private static final int SESSION_TIMEOUT=20*1000;
    
        /**
         * 创建连接
         * @return
         * @throws IOException
         */
    
        public ZooKeeper startZK() throws IOException {
            return new ZooKeeper(CONNECTSTRING, SESSION_TIMEOUT, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
    
                }
            });
        }
    
        /**
         * 关闭连接
         * @param zk
         * @throws InterruptedException
         */
    
        public void stopZK(ZooKeeper zk) throws InterruptedException {
            if (zk!=null){
                zk.close();
            }
        }
    
        /**
         * 创建zNode节点
         * @param zk
         * @param path
         * @param data
         * @throws KeeperException
         * @throws InterruptedException
         */
    
        public void createZNode(ZooKeeper zk , String path ,String data) throws KeeperException, InterruptedException {
            zk.create(path,data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    
        /**
         * 获取zNode
         * @param zk
         * @param path
         * @return
         * @throws KeeperException
         * @throws InterruptedException
         */
    
        public String getZNode(ZooKeeper zk,String path) throws KeeperException, InterruptedException {
            String result = "";
            byte[] data = zk.getData(path, false, new Stat());
            result = new String(data);
            return result;
        }
    
        public static void main(String[] args) throws Exception {
            WatchMore watchMore = new WatchMore();
            ZooKeeper zk = watchMore.startZK();
            if (zk.exists(PATH,false)==null){
                watchMore.createZNode(zk,PATH,"helloZK");
                String zNode = watchMore.getZNode(zk, PATH);
                System.out.println("zNode:"+zNode);
            }else{
                System.out.println("this zNode is created");
            }
            watchMore.stopZK(zk);
        }
    }
    

    四、通知机制

    1、通知机制:

    客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。

    2、观察者的功能watcher:

    ZooKeeper 支持watch(观察)的概念。客户端可以在每个znode结点上设置一个观察。如果被观察服务端的znode结点有变更,那么watch就会被触发,这个watch所属的客户端将接收到一个通知包被告知结点已经发生变化,把相应的事件通知给设置过Watcher的Client端。(一句话:异步回调的触发机制

    3、watch事件理解

    1. 一次触发:当数据有了变化时zkserver向客户端发送一个watch,它是一次性的动作,即触发一次就不再有效
    2. 发往客户端:Watches是异步发往客户端的,Zookeeper提供一个顺序保证:在看到watch事件之前绝不会看到变化,这样不同客户端看到的是一致性的顺序。
    3. 为数据设置watch:节点有不同的改动方式。可以认为ZooKeeper维护两个观察列表:数据观察和子节点观察。getData()和exists()设置数据观察。getChildren()设置子节点观察。此外,还可以认为不同的返回数据有不同的观察。getData()和exists()返回节点的数据,而getChildren()返回子节点列表。所以,setData()将为znode触发数据观察。成功的create()将为新创建的节点触发数据观察,为其父节点触发子节点观察。成功的delete()将会为被删除的节点触发数据观察以及子节点观察(因为节点不能再有子节点了),为其父节点触发子节点观察。
    4. 时序性和一致性:Watches是在client连接到Zookeeper服务端的本地维护,这可让watches成为轻量的,可维护的和派发的。当一个client连接到新server,watch将会触发任何session事件,断开连接后不能接收到。当客户端重连,先前注册的watches将会被重新注册并触发。、

    4、多次观察代码

    import org.apache.zookeeper.*;
    import org.apache.zookeeper.data.Stat;
    
    import java.io.IOException;
    
    /**
     * @Description:
     * @Auther: Tang
     * @Date: 2020/9/27 0027 下午 20:45
     */
    public class WatchMore {
    
        private static final String CONNECTSTRING = "39.99.144.224:2181";
        private static final String PATH = "/tang";
        private static final int SESSION_TIMEOUT=20*1000;
    
        private ZooKeeper zk;
    
        public ZooKeeper getZk() {
            return zk;
        }
    
        public void setZk(ZooKeeper zk) {
            this.zk = zk;
        }
    
        /**
         * 创建连接
         * @return
         * @throws IOException
         */
    
        public ZooKeeper startZK() throws IOException {
            return new ZooKeeper(CONNECTSTRING, SESSION_TIMEOUT, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
    
                }
            });
        }
    
        /**
         * 关闭连接
         * @throws InterruptedException
         */
    
        public void stopZK() throws InterruptedException {
            if (zk!=null){
                zk.close();
            }
        }
    
        /**
         * 创建zNode节点
         * @param path
         * @param data
         * @throws KeeperException
         * @throws InterruptedException
         */
    
        public void createZNode(String path ,String data) throws KeeperException, InterruptedException {
            zk.create(path,data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    
        /**
         * 获取zNode
         * @param path
         * @return
         * @throws KeeperException
         * @throws InterruptedException
         */
    
        public String getZNode(String path) throws Exception {
            String result = "";
            byte[] data = zk.getData(path, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    try {
                        triggerValue(path);
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, new Stat());
            result = new String(data);
            return result;
        }
    
        private void triggerValue(String path) throws KeeperException, InterruptedException {
            byte[] data = zk.getData(path, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    try {
                        triggerValue(path);
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, new Stat());
            String result = new String(data);
            System.out.println("triggerValue:"+result);
        }
    
        public static void main(String[] args) throws Exception {
            WatchMore watchMore = new WatchMore();
            ZooKeeper zk = watchMore.startZK();
            watchMore.setZk(zk);
            if (zk.exists(PATH,false)==null){
                watchMore.createZNode(PATH,"AAA");
                String zNode = watchMore.getZNode(PATH);
                System.out.println("zNode:"+zNode);
            }else{
                System.out.println("this zNode is created");
            }
            Thread.sleep(Long.MAX_VALUE);
        }
    }
    

    五、ZooKeeper集群

    1、伪分布式单机配置

    说明

    initLimit 是Zookeeper用它来限定集群中的Zookeeper服务器连接到Leader的时限

    syncLimit 限制了follower服务器与leader服务器之间请求和应答之间的时限

    配置步骤

    1. zookeeper-3.4.9.tar.gz解压后拷贝到/myzookeeper目录下并重新名为zk01,再复制zk01形成zk02、zk03,共计3份

    2. 进入zk01/02/03分别新建文件夹(mydata,mylog)

    3. 分别进入zk01-zk03各自的conf文件夹 新建zoo.cfg

    4. 编辑zoo.cfg
      设置自己的数据和log路径
      dataDir=/myzookeeper/zk01/mydata

      dataLogDir=/myzookeeper/zk01/mylog

      修改各自的clientPort

      在最后面添加server的列表

    5. 在各自mydata下面创建myid的文件,在里面写入server的数字

    6. 分别启动三个服务器

    7. zkCli连接server,带参数指定-server
      ./zkCli.sh -server 127.0.0.1:2193

      2191/2192/2193任意用客户端链接一台,会发现只需要有一个改变了,整个集群的内容自动一致性同步。

  • 相关阅读:
    JCreator的配置
    哈夫曼编码
    最小生成树
    逻辑左移右移与算术左移右移
    原码 反码 补码 移码
    hdu 小希的迷宫
    (二)Qt窗口应用程序Widget
    (一)Qt5模块,QtCreator常用快捷键,命名规范
    if __name__="__main__"
    数据库之sql语句汇总
  • 原文地址:https://www.cnblogs.com/xiaolaodi1999/p/13746676.html
Copyright © 2020-2023  润新知