zoukankan      html  css  js  c++  java
  • zookeeperCli和Java操作zookeeperAPI

      推荐一个zookeeper可视化工具:zktools.exe

      eclipse集成的工具: http://www.massedynamic.org/eclipse/updates/

    1.zkCli客户端基本操作(命令行操作)

     1.链接并查看基本命令

    .zkCli.cmd -server 127.0.0.1:2181

    其基本命令如下

    ZooKeeper -server host:port cmd args
            stat path [watch]
            set path data [version]
            ls path [watch]
            delquota [-n|-b] path
            ls2 path [watch]
            setAcl path acl
            setquota -n|-b val path
            history
            redo cmdno
            printwatches on|off
            delete path [version]
            sync path
            listquota path
            rmr path
            get path [watch]
            create [-s] [-e] path data acl
            addauth scheme auth
            quit
            getAcl path
            close
            connect host:port

    2.创建Znodes---  create

        用给定的路径创建一个znode。flag参数指定创建的znode是临时的,持久的还是顺序的。默认情况下,所有znode都是持久的。

       -e 参数指定是临时节点:当会话过期或客户端断开连接时,临时节点(flag:-e)将被自动删除。   

      -s 参数指定是顺序节点。 顺序节点保证znode路径将是唯一的。 ZooKeeper集合将向znode路径填充10位序列号。例如,znode路径 /myapp 将转换为/myapp0000000001,下一个序列号将为/myapp0000000002。如果没有指定flag,则znode被认为是持久的。

    语法

    create /path /data

    (1)创建永久节点(值的引号可有可无)

    [zk: 127.0.0.1:2181(CONNECTED) 4] create /test "testValue"
    Created /test

    (2)创建临时节点   加-e参数

    [zk: 127.0.0.1:2181(CONNECTED) 5] create -e /temp "tempValue"
    Created /temp

    (3)创建顺序节点   加  -s  参数

    [zk: 127.0.0.1:2181(CONNECTED) 6] create -s /queue "tqueueValue"
    Created /queue0000000003

    (4)创建临时顺序节点   加 -s -e 参数

    [zk: 127.0.0.1:2181(CONNECTED) 7] create -s -e /queueTmp "queueTmpValue"
    Created /queueTmp0000000004

    注意:

    (1)创建子节点的时候不能跨目录创建节点,也就是子节点必须在父节点存在的情况下创建。由于test22不存在所以第二个创建失败

    [zk: 127.0.0.1:2181(CONNECTED) 8] create /test/children1 "testChildrenValue"
    Created /test/children1
    [zk: 127.0.0.1:2181(CONNECTED) 9] create /test22/children1 "testChildrenValue"
    Node does not exist: /test22/children1

    (2)重复创建会失败

    [zk: 127.0.0.1:2181(CONNECTED) 17] create /test "tttt"
    Node already exists: /test

    查看上面创建的节点:

    [zk: 127.0.0.1:2181(CONNECTED) 10] ls /
    [queue0000000003, temp, zookeeper, test, queueTmp0000000004, FirstZnode]
    [zk: 127.0.0.1:2181(CONNECTED) 11] ls /test
    [children1]

    补充:如果想创建值为空的节点可以:

    [zk: 127.0.0.1:2181(CONNECTED) 119] create /null ""
    Created /null

    3.获取数据---get

    语法

    get /path 

      它返回znode的关联数据和指定znode的元数据。你将获得信息,例如上次修改数据的时间,修改的位置以及数据的相关信息。此CLI还用于分配监视器以显示数据相关的通知。要访问顺序节点,必须输入znode的完整路径。

    如下:

    [zk: 127.0.0.1:2181(CONNECTED) 14] get /test
    testValue
    cZxid = 0x300000002
    ctime = Fri Mar 08 11:27:48 CST 2019
    mZxid = 0x300000002
    mtime = Fri Mar 08 11:27:48 CST 2019
    pZxid = 0x300000006
    cversion = 1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 9
    numChildren = 1
    [zk: 127.0.0.1:2181(CONNECTED) 15] get /test/children1
    testChildrenValue
    cZxid = 0x300000006
    ctime = Fri Mar 08 11:33:05 CST 2019
    mZxid = 0x300000006
    mtime = Fri Mar 08 11:33:05 CST 2019
    pZxid = 0x300000006
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 17
    numChildren = 0
    [zk: 127.0.0.1:2181(CONNECTED) 16] get /queueTmp0000000004
    queueTmpValue
    cZxid = 0x300000005
    ctime = Fri Mar 08 11:31:55 CST 2019
    mZxid = 0x300000005
    mtime = Fri Mar 08 11:31:55 CST 2019
    pZxid = 0x300000005
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x10038e5aa8c0000
    dataLength = 13
    numChildren = 0

    4. Watch  监视节点

       当指定的znode或znode的子数据更改时,监视器会显示通知。你只能在 get 命令中设置watch

     语法:

    get /path [watch] 1

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 18] get /test 1
    testValue
    cZxid = 0x300000002
    ctime = Fri Mar 08 11:27:48 CST 2019
    mZxid = 0x300000002
    mtime = Fri Mar 08 11:27:48 CST 2019
    pZxid = 0x300000006
    cversion = 1
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 9
    numChildren = 1

      输出类似于普通的 get 命令,但它会等待后台等待znode更改。<从这里开始>

    5.  设置数据(相当于修改值)---set

      设置指定znode的数据。完成此设置操作后,你可以使用 get CLI命令检查数据。如果你在 get 命令中分配了watch选项(如上一个命令),则输出监视信息

    语法

    set /path /data

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 19] set /test tttt
    
    WATCHER::
    cZxid = 0x300000002
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/test
    
    ctime = Fri Mar 08 11:27:48 CST 2019
    mZxid = 0x300000009
    mtime = Fri Mar 08 11:44:03 CST 2019
    pZxid = 0x300000006
    cversion = 1
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 4
    numChildren = 1
    [zk: 127.0.0.1:2181(CONNECTED) 20] get /test
    tttt
    cZxid = 0x300000002
    ctime = Fri Mar 08 11:27:48 CST 2019
    mZxid = 0x300000009
    mtime = Fri Mar 08 11:44:03 CST 2019
    pZxid = 0x300000006
    cversion = 1
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 4
    numChildren = 1

    6.列出节点---ls

      此命令用于列出和显示znode的子项。

    语法:

    ls /path

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 24] ls /
    [queue0000000003, temp, zookeeper, test, queueTmp0000000004, FirstZnode]
    [zk: 127.0.0.1:2181(CONNECTED) 25] ls /test
    [children1]
    [zk: 127.0.0.1:2181(CONNECTED) 27] ls /test/children1
    []

    7.检查状态---stat

     状态描述指定的znode的元数据。它包含时间戳,版本号,ACL,数据长度和子znode等细项。

    语法:

    stat /path

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 28] stat /test
    cZxid = 0x300000002
    ctime = Fri Mar 08 11:27:48 CST 2019
    mZxid = 0x300000009
    mtime = Fri Mar 08 11:44:03 CST 2019
    pZxid = 0x300000006
    cversion = 1
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 4
    numChildren = 1

    8.移除Znode---rmr(有节点也可以删)

      移除指定的znode并递归其所有子节点。只有在这样的znode可用的情况下才会发生。有子节点删除父节点是可以删除成功的。

    语法:

    rmr /path

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 30] rmr /temp
    [zk: 127.0.0.1:2181(CONNECTED) 31] ls /
    [queue0000000003, zookeeper, test, queueTmp0000000004, FirstZnode]
    [zk: 127.0.0.1:2181(CONNECTED) 32] rmr /test
    [zk: 127.0.0.1:2181(CONNECTED) 33] ls /
    [queue0000000003, zookeeper, queueTmp0000000004, FirstZnode]

    9.删除节点---delete(只能删除没有子节点的节点)

    语法:

    delete /path

    例如:

    [zk: 127.0.0.1:2181(CONNECTED) 63] ls /1
    [2]
    [zk: 127.0.0.1:2181(CONNECTED) 64] delete /1
    Node not empty: /1
    [zk: 127.0.0.1:2181(CONNECTED) 68] delete /1/2
    [zk: 127.0.0.1:2181(CONNECTED) 69] delete /1
    [zk: 127.0.0.1:2181(CONNECTED) 70] ls /
    [queue0000000003, zookeeper, queueTmp0000000004, FirstZnode]

     

    2.Java连接zookeeper进行操作API

    maven坐标:

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

     1.基础知识

      与ZooKeeper集合进行交互的应用程序称为 ZooKeeper客户端或简称客户端。
      客户端应该遵循以步骤,与ZooKeeper集合进行清晰和干净的交互。
        (1)连接到ZooKeeper集合。ZooKeeper集合为客户端分配会话ID。
        (2)定期向服务器发送心跳。否则,ZooKeeper集合将过期会话ID,客户端需要重新连接。
        (3)只要会话ID处于活动状态,就可以获取/设置znode。
        (4)所有任务完成后,断开与ZooKeeper集合的连接。如果客户端长时间不活动,则ZooKeeper集合将自动断开客户端。

    (1)zookeeper客户端与zookeeper server连接的状态有下面几种:

      KeeperState.Expired         客户端和服务器在ticktime的时间周期内,是要发送心跳通知的。这是租约协议的一个实现。客户端发送request,告诉服务器其上一个租约时间,服务器收到这个请求后,告诉客户端其下一个租约时间是哪个时间点。当客户端时间戳达到最后一个租约时间,而没有收到服务器发来的任何新租约时间,即认为自己下线(此后客户端会废弃这次连接,并试图重新建立连接)。这个过期状态就是Expired状态
      KeeperState.Disconnected   就像上面那个状态所述,当客户端断开一个连接(可能是租约期满,也可能是客户端主动断开)这是客户端和服务器的连接就是Disconnected状态
      KeeperState.SyncConnected    一旦客户端和服务器的某一个节点建立连接(注意,虽然集群有多个节点,但是客户端一次连接到一个节点就行了),并完成一次version、zxid的同步,这时的客户端和服务器的连接状态就是SyncConnected
      KeeperState.AuthFailed        zookeeper客户端进行连接认证失败时,发生该状态

      需要说明的是,这些状态在触发时,所记录的事件类型都是:EventType.None

    (2)事件类型WatchedEvent.getType()有下面五种:是Event的一个内部枚举类。当zookeeper客户端监听某个znode节点”/node-x”时:

            public enum EventType {
                None (-1),
                NodeCreated (1),
                NodeDeleted (2),
                NodeDataChanged (3),
                NodeChildrenChanged (4);
        ...
    }

    解释如下:

    EventType.NodeCreated 当node-x这个节点被创建时,该事件被触发
    EventType.NodeChildrenChanged 当node-x这个节点的直接子节点被创建、被删除、子节点数据发生变更时,该事件被触发。
    EventType.NodeDataChanged 当node-x这个节点的数据发生变更时,该事件被触发
    EventType.NodeDeleted 当node-x这个节点被删除时,该事件被触发。
    EventType.None 当zookeeper客户端的连接状态发生变更时,即KeeperState.Expired、KeeperState.Disconnected、KeeperState.SyncConnected、KeeperState.AuthFailed状态切换时,描述的事件类型为EventType.None

    2.Java连接zookeeper

      ZooKeeper API的核心部分是ZooKeeper类。它提供了在其构造函数中连接ZooKeeper集合的选项,并具有以下方法:

    • connect - 连接到ZooKeeper集合

    • create- 创建znode

    • exists- 检查znode是否存在及其信息

    • getData - 从特定的znode获取数据

    • setData - 在特定的znode中设置数据

    • getChildren - 获取特定znode中的所有子节点

    • delete - 删除特定的znode及其所有子项

    • close - 关闭连接

    ZooKeeper类通过其构造函数提供connect功能。构造函数的签名如下 :

    ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
    • connectionString - ZooKeeper集合主机。

    • sessionTimeout - 会话超时(以毫秒为单位)。

    • watcher - 实现“监视器”界面的对象。ZooKeeper集合通过监视器对象返回连接状态。

    如下连接代码:

      当然其链接地址可以改为集群:127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

    package zookeper;
    
    import java.io.IOException;
    import java.util.concurrent.CountDownLatch;
    
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.KeeperException;
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.Watcher.Event.KeeperState;
    import org.apache.zookeeper.ZooDefs;
    import org.apache.zookeeper.ZooKeeper;
    
    public class BaseAPI {
        private static ZooKeeper zoo;
        final static CountDownLatch connectedSignal = new CountDownLatch(1);
    
        public static ZooKeeper connect(String host) throws IOException, InterruptedException {
            zoo = new ZooKeeper(host, 5000, new Watcher() {
                public void process(WatchedEvent we) {
                    if (we.getState() == KeeperState.SyncConnected) {
                        connectedSignal.countDown();
                    }
                }
            });
    
            connectedSignal.await();
            return zoo;
        }
    
        public void close() throws InterruptedException {
            zoo.close();
        }
    
        public static void create(String path, byte[] data) throws KeeperException, InterruptedException {
            zoo.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    
        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
        }
    }

      解释:因为链接zookeper是一个异步的过程,所以用闭锁来阻塞主线程。

        这里 CountDownLatch 用于停止(等待)主进程,直到客户端与ZooKeeper集合连接。ZooKeeper集合通过监视器回调来回复连接状态。一旦客户端与ZooKeeper集合连接,监视器回调就会被调用,并且监视器回调函数调用CountDownLatchcountDown方法来释放锁,在主进程中await

    3.创建节点:

      ZooKeeper类提供了在ZooKeeper集合中创建一个新的znode的create方法。 create 方法的签名如下:

    • path - Znode路径。例如,/myapp1,/myapp2,/myapp1/mydata1,myapp2/mydata1/myanothersubdata

    • data - 要存储在指定znode路径中的数据(要转为字节数组byte[]进行存储)

    • acl - 要创建的节点的访问控制列表。ZooKeeper API提供了一个静态接口 ZooDefs.Ids 来获取一些基本的acl列表。例如,ZooDefs.Ids.OPEN_ACL_UNSAFE返回打开znode的acl列表。

    • createMode - 节点的类型,即临时,顺序或两者。这是一个枚举

            ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
            String ret = zoo.create("/javacreate", "javacreateValue".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
            System.out.println(ret);

    结果:(可见创建节点返回的是节点的路径)

    =================连接成功===============
    /javacreate

    重复创建节点会报错如下:

    =================连接成功===============
    Exception in thread "main" org.apache.zookeeper.KeeperException$NodeExistsException: KeeperErrorCode = NodeExists for /javacreate
        at org.apache.zookeeper.KeeperException.create(KeeperException.java:119)
        at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
        at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:783)
        at zookeper.BaseAPI.main(BaseAPI.java:42)

    4.  Exists - 检查Znode的存在与获取数据的stat信息(可以注册监听)

      ZooKeeper类提供了 exists 方法来检查znode的存在。如果指定的znode存在,则返回一个znode的元数据stat

    exists(String path, boolean watcher)
    • path- Znode路径

    • watcher - 布尔值,用于指定是否监视指定的znode

    例如:

            ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
            Stat exists = connect.exists("/javacreate", true);
            System.out.println(exists);

    结果: (如果访问一个不存在的节点返回的是null)

    =================连接成功===============
    12884901917,12884901917,1552024345963,1552024345963,0,0,0,0,15,0,12884901917

    stat可以获取版本以及其他有用信息

    5. setData方法 修改节点

      ZooKeeper类提供 setData 方法来修改指定znode中附加的数据。 setData 方法的签名如下:

    setData(String path, byte[] data, int version)
    • path- Znode路径

    • data - 要存储在指定znode路径中的数据。

    • version- znode的当前版本。每当数据更改时,ZooKeeper会更新znode的版本号。(必须传入正确的版本)

     如下:

            final String path = "/javacreate";
            final ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
            Stat stat = connect.exists("/javacreate", true);
            Stat setData = connect.setData("/javacreate", "vvvv222".getBytes(), stat.getVersion());

    6. getChildren方法--获取所有的子节点(可以注册监听)

    getChildren(String path, Watcher watcher)
    • path - Znode路径。

    • watcher - 监视器类型的回调函数。当指定的znode被删除或znode下的子节点被创建/删除时,ZooKeeper集合将进行通知。这是一次性通知。

    注意:

    (1)当节点不存在时直接获取会报错

    (2)获取的只是下面的一级子节点,也就是对于子节点的子节点是获取不到的

    (3)监听的事件也是只能监听到字目录节点的数量变化、监听不到子子目录的变化。

    测试代码:

        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            final String path = "/key1";
            final ZooKeeper connect = connect("127.0.0.1:2181");
            final CountDownLatch latch = new CountDownLatch(1);
            // 获取子节点不注册监听
            List<String> children2 = connect.getChildren(path, false);
            System.out.println(children2);
    
            // 获取子节点注册监听
            connect.getChildren(path, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    // 1打印一下事件
                    System.out.println(event);
                    // 如果事件类型为none,且连接状态为超时就退出且闭锁减一(实际上还可以监听更多的事件,比如说节点修改、节点删除等事件并作出相应的操作)
                    if (event.getType() == Event.EventType.None) {
                        switch (event.getState()) {
                        case Expired:
                            break;
                        }
    
                    } else {// 2如果事件类型不是NONE就打印一下事件且重新获取数据并且闭锁减一
                        try {
                            System.out.println("监听到的事件类型是:" + event.getType());
                            // 再次注册监听
                            byte[] bn = connect.getData(path, new MyWatcher(connect, path), null);
                            String data = new String(bn, "UTF-8");
                            System.out.println(data);
                            latch.countDown();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
    
            latch.await();
        }

    6. 删除Znode

    delete(String path, int version)
    • path - Znode路径。

    • version - znode的当前版本。

    注意:如果传的version不正确会报错

    如下:

    connect.delete("/javacreate", connect.exists(path, false).getVersion());

    7.  getData方法 获取数据(可以注册监听)

      支持同步获取和异步获取,四个方法如下:

    (1)同步获取方法

      ZooKeeper类提供 getData 方法来获取附加在指定znode中的数据及其状态。 getData 方法的签名如下:

    byte[] getData(String path, boolean watch, Stat stat)
    byte[] getData(final String path, Watcher watcher, Stat stat)

    (2)异步获取方法

    void getData(final String path, Watcher watcher,
                DataCallback cb, Object ctx)

    public void getData(String path, boolean watch, DataCallback cb, Object ctx) { getData(path, watch ? watchManager.defaultWatcher : null, cb, ctx); }

    参数解释

    path     指定数据节点的路径,获取该节点下面的子节点
    watcher 注册在path上的Watcher。节点变更会通知会向客户端发起通知。
    stat     指定数据节点状态信息。传入旧stat,方法执行过程中会将其替换为新stat对象。(获取方法可以用上面介绍过的exists获取)
    watch   表示是否需要注册一个watcher。true:注册默认watcher,false:不需要注册watcher
    cb    注册一个异步回调函数
    ctx   传递上下文信息

    获取数据且监听节点的测试如下:(重要)

        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            final CountDownLatch latch = new CountDownLatch(1);
            final String path = "/javacreate";
            final ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
    
            // 1.获取元数据stat
            Stat znodeStat = connect.exists(path, false);
    
            // 2.同步获取数据且不监听但是覆盖stat
            byte[] data = connect.getData(path, false, znodeStat);
            System.out.println(new String(data, "UTF-8"));
    
            // 3.同步获取数据且监听不覆盖stat
            byte[] data2 = connect.getData(path, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    // 3.1打印一下事件
                    System.out.println(event);
                    // 如果事件类型为none,且连接状态为超时就退出且闭锁减一(实际上还可以监听更多的事件,比如说节点修改、节点删除等事件并作出相应的操作)
                    if (event.getType() == Event.EventType.None) {
                        switch (event.getState()) {
                        case Expired:
                            latch.countDown();
                            break;
                        }
    
                    } else {// 3.2如果事件类型不是NONE就打印一下事件且重新获取数据并且闭锁减一
                        try {
                            System.out.println("监听到的事件类型是:" + event.getType());
                            byte[] bn = connect.getData(path, false, null);
                            String data = new String(bn, "UTF-8");
                            System.out.println(data);
                            latch.countDown();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, null);
    
            // 阻塞等待事件变化
            latch.await();
        }

    结果:

    =================连接成功===============
    22233444
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate

    我们通过zkCli修改此节点:

    [zk: 127.0.0.1:2181(CONNECTED) 82] set /javacreate 22233444555
    cZxid = 0x30000001d
    ctime = Fri Mar 08 13:52:25 CST 2019
    mZxid = 0x300000053
    mtime = Fri Mar 08 14:58:04 CST 2019
    pZxid = 0x30000001d
    cversion = 0
    dataVersion = 8
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 11
    numChildren = 0

    java监听到节点修改事件并且控制台信息变为如下:

    =================连接成功===============
    22233444
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate
    监听到的事件类型是:NodeDataChanged
    22233444555

    补充:异步创建节点的例子

      在原来的基础上增加两个参数即可,第一个是异步回调,需要实现  StringCallback  接口,最后一个接口是上下文环境。

        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            final String path = "/javacreate2";
            final ZooKeeper connect = connect("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183");
            connect.create(path, "111".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT,
                    new StringCallback() {
                        @Override
                        public void processResult(int rc, String path, Object ctx, String name) {
                            System.out.println("create path result:[" + rc + ", " + path + "," + ctx + ", real path name "
                                    + name + " ]");
                        }
                    }, "context");
            
            Thread.sleep(10*1000);
        }

    结果:

    create path result:[0, /javacreate2,context, real path name /javacreate2 ]

    补充关于建监听做下面补充:

    (1)  监控同一个节点X的一个watcher实例,通过exist、getData等注册方式多次注册的,zkClient也只会通知一次。zkClient是不是做多次watcher通知,和使用什么方法注册的没有关系,关键在于所注册的watcher实例是否为同一个实例。

    (2) 当一个节点还不存在时,zk.getData这样设置的watcher是会抛出KeeperException$NoNodeException异常的,这次注册会失败,watcher也不会起作用。也就是通过getData()监听一个不存在的节点会报错如下:

    Exception in thread "main" org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /javacreate111
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:111)
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
    at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1212)
    at zookeper.BaseAPI.main(BaseAPI.java:48)

    (3)zookeeper中并没有“永久监听”这种机制。但是可以通过自行编程实现。

      思路可以归为两类:一种是“在保证所有节点的watcher都被重新注册”的前提下,再进行目录、子目录的更改;另外一种是“在监听被触发后,被重新注册前,重新取一次节点的信息”确保在“监听真空期”znode没有变化。

    (4)关于可监听事件与对应方法如下:(只能在下面三个方法中进行监听节点)

    注册方式NodeCreatedNodeChildrenChangedNodeDataChangedEventType.NodeDeleted
    zk.getChildren(“/node-x”,watcher)   可监控   可监控
    zk.exists(“/node-x”,watcher) 可监控   可监控 可监控
    zk.getData(“/node-x”,watcher)     可监控 可监控

    补充:永久监听的一个简单实现

      其实现思路就是在监听器的处理事件里面再次注册监听器,如下就是一个简单的实现:

    package zookeper;
    
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooKeeper;
    
    public class MyWatcher implements Watcher {
    
        private ZooKeeper connect;
        private String path;
    
        public MyWatcher(ZooKeeper connect, String path) {
            super();
            this.connect = connect;
            this.path = path;
        }
    
        @Override
        public void process(WatchedEvent event) {
            // 1打印一下事件
            System.out.println(event);
            // 如果事件类型为none,且连接状态为超时就退出且闭锁减一(实际上还可以监听更多的事件,比如说节点修改、节点删除等事件并作出相应的操作)
            if (event.getType() == Event.EventType.None) {
                switch (event.getState()) {
                case Expired:
                    break;
                }
    
            } else {// 2如果事件类型不是NONE就打印一下事件且重新获取数据并且闭锁减一
                try {
                    System.out.println("监听到的事件类型是:" + event.getType());
                    // 再次注册监听
                    byte[] bn = connect.getData(path, new MyWatcher(connect, path), null);
                    String data = new String(bn, "UTF-8");
                    System.out.println(data);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    }

    测试代码:

            final CountDownLatch latch = new CountDownLatch(1);
            final String path = "/javacreate";
            final ZooKeeper connect = connect("127.0.0.1:2181");
            System.out.println("=================连接成功===============");
    
            // 3.同步获取数据且监听不覆盖stat
            MyWatcher myWatcher = new MyWatcher(connect, path);
            connect.exists(path, myWatcher);
    
            // 阻塞
            latch.await();

    我们在zkCli客户端多次修改节点查看结果:

    =================连接成功===============
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate
    监听到的事件类型是:NodeDataChanged
    336
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate
    监听到的事件类型是:NodeDataChanged
    336
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate
    监听到的事件类型是:NodeDataChanged
    336
    WatchedEvent state:SyncConnected type:NodeDataChanged path:/javacreate
    监听到的事件类型是:NodeDataChanged
    336

  • 相关阅读:
    2.采用字符的移位方式实现字符文本加密解密。
    用自己的算法实现startsWith和endsWith功能。
    采用多种算法,模拟摇奖:从1-36中随机抽出8个不重复的数字
    输入5个数用冒泡排序进行从小到大排列
    题目六:控制台输入年龄,根据年龄输出不同的提示
    题目五:控制台输出三角形和菱形
    题目四:控制台输出九九乘法表
    百马百担
    classNum 表示学生的班号,例如“class05”。 有如下List  List list = new ArrayList();
    已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数     2008 北京奥运会男足参赛国家:  科特迪瓦,阿根廷,澳大利亚,塞尔维亚,荷兰,尼日利亚、日本,美国,中国,新西 兰,巴西,比利时,韩国,喀麦隆,洪都拉斯,意大利
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10494944.html
Copyright © 2011-2022 走看看