Operate ZooKeeper using the Java API provided by ZooKeeper

Establish a connection between the client and the zk server

Let's create a normal maven project first, and then configure the zookeeper dependencies in the pom.xml file:

<dependencies>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.11</version>
    </dependency>
</dependencies>

Create a zk-connect.properties property configuration file in the resources directory, in which we fill in some configuration information for connecting to the zookeeper server. as follows:

# zk.zkServerIp=192.168.190.129:2181  单机模式
zk.zkServerIps=192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181
zk.timeout=5000

Note: I am using cluster mode here, so there are multiple IPs.

zookeeper uses log4j as a log printing tool, so we also need to create log4j in the resources directory

log4j.rootLogger=WARN,console

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.encoding=UTF-8
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%l] - [%p] %m%n

Then create a connection class demo with the following code:

package org.zero01.zk.demo;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;

/**
 * @Description: zookeeper 连接demo演示
 */
public class ZKConnect implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZKConnect.class);

    // private static String zkServerIp;  单机模式是一个ip

    // 集群模式则是多个ip
    private static String zkServerIps;

    // 连接超时时间
    private static Integer timeout;

    // 加载配置信息
    static {
        Properties properties = new Properties();
        InputStream inputStream = Object.class.getResourceAsStream("/zk-connect.properties");
        try {
            properties.load(inputStream);

            // zkServerIp = properties.getProperty("zk.zkServerIp");
            zkServerIps = properties.getProperty("zk.zkServerIps");
            timeout = Integer.parseInt(properties.getProperty("zk.timeout"));
        } catch (Exception e) {
            logger.error("配置文件读取异常", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                logger.error("关闭流失败", e);
            }
        }
    }

    // Watch事件通知
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        /**
         * 客户端和zk服务端链接是一个异步的过程
         * 当连接成功后后,客户端会收的一个watch通知
         *
         * 参数:
         * connectString:连接服务器的ip字符串,
         *      比如: "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181"
         *      可以是一个ip,也可以是多个ip,一个ip代表单机,多个ip代表集群
         *      也可以在ip后加路径
         * sessionTimeout:超时时间,心跳收不到了,那就超时
         * watcher:通知事件,如果有对应的事件触发,则会收到一个通知;如果不需要,那就设置为null
         * canBeReadOnly:可读,当这个物理机节点断开后,还是可以读到数据的,只是不能写,
         *                         此时数据被读取到的可能是旧数据,此处建议设置为false,不推荐使用
         * sessionId:会话的id
         * sessionPasswd:会话密码   当会话丢失后,可以依据 sessionId 和 sessionPasswd 重新获取会话
         */

        // 实例化zookeeper客户端
        ZooKeeper zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKConnect());

        logger.warn("客户端开始连接zookeeper服务器...");
        logger.warn("连接状态:{}", zooKeeper.getState());

        // 避免发出连接请求就断开,不然就无法正常连接也无法获取watch事件的通知
        Thread.sleep(2000);

        logger.warn("连接状态:{}", zooKeeper.getState());
    }
}

After running this class, the console output log information is as follows:

2018-04-25 10:41:32,488 [main] [org.zero01.zk.demo.ZKConnect.main(ZKConnect.java:76)] - [WARN] 客户端开始连接zookeeper服务器...
2018-04-25 10:41:32,505 [main] [org.zero01.zk.demo.ZKConnect.main(ZKConnect.java:77)] - [WARN] 连接状态:CONNECTING
2018-04-25 10:41:32,515 [main-EventThread] [org.zero01.zk.demo.ZKConnect.process(ZKConnect.java:52)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
2018-04-25 10:41:34,507 [main] [org.zero01.zk.demo.ZKConnect.main(ZKConnect.java:81)] - [WARN] 连接状态:CONNECTED

In this way, we have completed the process of establishing a connection with the zookeeper server.


zk session reconnection mechanism

In the previous section, we briefly demonstrated how to connect to the zk server. In this section, we will introduce how to restore the previous session through the sessionid and session password, that is, the session reconnection mechanism of zk.

Create a new class to use as a demo to demonstrate the zk session reconnection mechanism:

package org.zero01.zk.demo;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @program: zookeeper-connection
 * @description: zookeeper 恢复之前的会话连接demo演示
 * @author: 01
 * @create: 2018-04-25 12:59
 **/
public class ZKConnectSessionWatcher implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZKConnectSessionWatcher.class);

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;

    // Watch事件通知
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        // 实例化zookeeper客户端
        ZooKeeper zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKConnectSessionWatcher());

        logger.warn("客户端开始连接zookeeper服务器...");
        logger.warn("连接状态:{}", zooKeeper.getState());
        Thread.sleep(2000);
        logger.warn("连接状态:{}", zooKeeper.getState());

        // 记录本次会话的sessionId
        long sessionId = zooKeeper.getSessionId();
        // 转换成16进制进行打印
        logger.warn("sid:{}", "0x" + Long.toHexString(sessionId));
        // 记录本次会话的session密码
        byte[] sessionPassword = zooKeeper.getSessionPasswd();

        Thread.sleep(200);

        // 开始会话重连
        logger.warn("开始会话重连...");
        // 加上sessionId和password参数去实例化zookeeper客户端
        ZooKeeper zkSession = new ZooKeeper(zkServerIps, timeout, new ZKConnectSessionWatcher(), sessionId, sessionPassword);
        logger.warn("重新连接状态zkSession:{}", zkSession.getState());
        Thread.sleep(2000);
        logger.warn("重新连接状态zkSession:{}", zkSession.getState());
    }
}

Running this class, the console output log results are as follows:

2018-04-25 13:48:00,931 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:35)] - [WARN] 客户端开始连接zookeeper服务器...
2018-04-25 13:48:00,935 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:36)] - [WARN] 连接状态:CONNECTING
2018-04-25 13:48:00,951 [main-EventThread] [org.zero01.zk.demo.ZKConnectSessionWatcher.process(ZKConnectSessionWatcher.java:28)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
2018-04-25 13:48:02,935 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:38)] - [WARN] 连接状态:CONNECTED
2018-04-25 13:48:02,935 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:43)] - [WARN] sid:0x10000e81cfa0002
2018-04-25 13:48:03,136 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:50)] - [WARN] 开始会话重连...
2018-04-25 13:48:03,137 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:53)] - [WARN] 重新连接状态zkSession:CONNECTING
2018-04-25 13:48:03,142 [main-EventThread] [org.zero01.zk.demo.ZKConnectSessionWatcher.process(ZKConnectSessionWatcher.java:28)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
2018-04-25 13:48:05,140 [main] [org.zero01.zk.demo.ZKConnectSessionWatcher.main(ZKConnectSessionWatcher.java:55)] - [WARN] 重新连接状态zkSession:CONNECTED

Create zk nodes synchronously/asynchronously

Above we have introduced how to connect and reconnect to the zk server. Now that we know how to connect to the zk server, let's see how to create a zk node synchronously or asynchronously.

First demonstrate the way to create zk nodes synchronously, create a demo class as follows:

package org.zero01.zk.demo;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;

/**
 * @program: zookeeper-connection
 * @description:  演示同步异步创建zk节点
 * @author: 01
 * @create: 2018-04-25 13:51
 **/
public class ZkNodeOperator implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZkNodeOperator.class);

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private ZooKeeper zooKeeper;

    public ZooKeeper getZooKeeper() {
        return zooKeeper;
    }

    public void setZooKeeper(ZooKeeper zooKeeper) {
        this.zooKeeper = zooKeeper;
    }

    public ZkNodeOperator() {
    }

    public ZkNodeOperator(String connectStr) {
        try {
            // 在使用该构造器的时候,实例化zk客户端对象
            zooKeeper = new ZooKeeper(connectStr, timeout, new ZkNodeOperator());
        } catch (IOException e) {
            e.printStackTrace();
            try {
                if (zooKeeper != null) {
                    zooKeeper.close();
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    /**
     * @Title: ZKOperatorDemo.java
     * @Description: 创建zk节点
     */
    public void createZKNode(String path, byte[] data, List<ACL> acls) {
        String result = "";
        try {
            /**
             * 同步或者异步创建节点,都不支持子节点的递归创建,异步有一个callback函数
             * 参数:
             * path:节点创建的路径
             * data:节点所存储的数据的byte[]
             * acl:控制权限策略
             *          Ids.OPEN_ACL_UNSAFE --> world:anyone:cdrwa
             *          CREATOR_ALL_ACL --> auth:user:password:cdrwa
             * createMode:节点类型, 是一个枚举
             *          PERSISTENT:持久节点
             *          PERSISTENT_SEQUENTIAL:持久顺序节点
             *          EPHEMERAL:临时节点
             *          EPHEMERAL_SEQUENTIAL:临时顺序节点
             */
            // 同步创建zk节点,节点类型为临时节点
            result = zooKeeper.create(path, data, acls, CreateMode.EPHEMERAL);
            System.out.println("创建节点:\t" + result + "\t成功...");
            Thread.sleep(2000);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ZkNodeOperator zkServer = new ZkNodeOperator(zkServerIps);

        // 创建zk节点
        zkServer.createZKNode("/testNode", "testNode-data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE);
    }
}

Run the class and go to the server to see if it has been created successfully. As follows, I have successfully created it here:

[root@zk001 ~]# zkCli.sh
[zk: localhost:2181(CONNECTED) 7] ls /
[zookeeper, data, real-culster, testNode]
[zk: localhost:2181(CONNECTED) 8] ls /
[zookeeper, data, real-culster]  # 因为是临时节点,所以客户端断开之后就消失了
[zk: localhost:2181(CONNECTED) 9] quit
[root@zk001 ~]# 

The log information output by the console is as follows:

2018-04-25 14:16:47,726 [main-EventThread] [org.zero01.zk.demo.ZkNodeOperator.process(ZkNodeOperator.java:56)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
创建节点:   /testNode   成功...

Next, we will demonstrate how to create a zk node asynchronously. Because there is a callback function for asynchronous creation, we must first create a class to implement the callback method in the StringCallback interface:

package org.zero01.zk.demo;

import org.apache.zookeeper.AsyncCallback.StringCallback;

public class CreateCallBack implements StringCallback {

    // 回调函数
    public void processResult(int rc, String path, Object ctx, String name) {
        System.out.println("创建节点:" + path);
        System.out.println((String) ctx);
    }
}

Modify the code of the createZKNode method in the ZkNodeOperator class as follows:

...
public class ZkNodeOperator implements Watcher {
    ...
    /**
     * @Title: ZKOperatorDemo.java
     * @Description: 创建zk节点
     */
    public void createZKNode(String path, byte[] data, List<ACL> acls) {
        try {
            ...
            // 异步步创建zk节点,节点类型为持久节点
            String ctx = "{'create':'success'}";
            zooKeeper.create(path, data, acls, CreateMode.PERSISTENT, new CreateCallBack(), ctx);

            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}    

Run the class, and then go to the server to see if it has been created successfully. As follows, I have successfully created it here:

[zk: localhost:2181(CONNECTED) 9] ls /
[zookeeper, data, real-culster, testNode]
[zk: localhost:2181(CONNECTED) 10] get /testNode
testNode-data
cZxid = 0x700000014
ctime = Wed Apr 25 22:17:26 CST 2018
mZxid = 0x700000014
mtime = Wed Apr 25 22:17:26 CST 2018
pZxid = 0x700000014
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0
[zk: localhost:2181(CONNECTED) 11] 

The log information output by the console is as follows:

2018-04-25 14:25:14,923 [main-EventThread] [org.zero01.zk.demo.ZkNodeOperator.process(ZkNodeOperator.java:56)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
创建节点:/testNode
{'create':'success'}

Modify zk node data synchronously/asynchronously

Similarly, we can also modify the data of the zk node through the Java API provided by Zookeeper. There are also two ways: synchronous and asynchronous. Let’s first demonstrate the synchronous way. Create a new class with the following code:

package org.zero01.zk.demo;

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @program: zookeeper-connection
 * @description: 修改zk节点数据演示
 * @author: 01
 * @create: 2018-04-25 16:25
 **/
public class ZKNodeAlterOperator implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZKNodeAlterOperator.class);

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private ZooKeeper zooKeeper;

    public ZooKeeper getZooKeeper() {
        return zooKeeper;
    }

    public void setZooKeeper(ZooKeeper zooKeeper) {
        this.zooKeeper = zooKeeper;
    }

    public ZKNodeAlterOperator() {
    }

    public ZKNodeAlterOperator(String connectStr) {
        try {
            // 在使用该构造器的时候,实例化zk客户端对象
            zooKeeper = new ZooKeeper(connectStr, timeout, new ZKNodeAlterOperator());
        } catch (IOException e) {
            e.printStackTrace();
            try {
                if (zooKeeper != null) {
                    zooKeeper.close();
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    public static void main(String[] args) throws KeeperException, InterruptedException {
        ZKNodeAlterOperator zkServer = new ZKNodeAlterOperator(zkServerIps);

        /**
         * 修改zk节点数据(同步)
         * 参数:
         * path:节点路径
         * data:新数据
         * version 数据版本
         */
        Stat status = zkServer.getZooKeeper().setData("/testNode", "this is new data".getBytes(), 0);
        // 通过Stat对象可以获取znode所有的状态属性,这里以version为例
        System.out.println("修改成功,当前数据版本为:" + status.getVersion());
    }
}

Run this class to check whether the node has successfully modified the data on the server. As follows, I have successfully modified it here:

[zk: localhost:2181(CONNECTED) 12] get /testNode
this is new data
cZxid = 0x700000014
ctime = Wed Apr 25 22:17:26 CST 2018
mZxid = 0x700000017
mtime = Thu Apr 26 00:21:54 CST 2018
pZxid = 0x700000014
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 16
numChildren = 0
[zk: localhost:2181(CONNECTED) 13] 

The log information output by the console is as follows:

2018-04-25 16:30:02,111 [main-EventThread] [org.zero01.zk.demo.ZkNodeOperator.process(ZkNodeOperator.java:57)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
修改成功,当前数据版本为:1

Next, we will demonstrate how to modify zk node data asynchronously, which is almost the same as creating nodes asynchronously. It is also necessary to create a new class to implement the callback interface method, but the interface is different. as follows:

package org.zero01.zk.demo;

import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.data.Stat;

public class AlterCallBack implements StatCallback {

    // 回调函数
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        System.out.println("修改节点:" + path + "成功...");
        // 通过Stat对象可以获取znode所有的状态属性,这里以version为例
        System.out.println("当前数据版本为:" + stat.getVersion());
        System.out.println((String) ctx);
    }
}

Then modify the main method code in the ZKNodeAlterOperator class as follows:

...
public class ZKNodeAlterOperator implements Watcher {
    ...
    public static void main(String[] args) throws KeeperException, InterruptedException {
        ZKNodeAlterOperator zkServer = new ZKNodeAlterOperator(zkServerIps);

        /**
         * 修改zk节点数据(异步)
         * 参数:
         * path:节点路径
         * data:新数据
         * version: 数据版本
         * sc:实现回调函数的对象
         * ctx:给回调函数的上下文
         */
        String ctx = "{'alter':'success'}";
        zkServer.getZooKeeper().setData("/testNode", "asynchronous-data".getBytes(), 0, new AlterCallBack(), ctx);

        Thread.sleep(2000);
    }
}

Run this class to check whether the node has successfully modified the data on the server. As follows, I have successfully modified it here:

[zk: localhost:2181(CONNECTED) 16] get /testNode
asynchronous-data
cZxid = 0x700000014
ctime = Wed Apr 25 22:17:26 CST 2018
mZxid = 0x70000001a
mtime = Thu Apr 26 00:35:53 CST 2018
pZxid = 0x700000014
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 17
numChildren = 0
[zk: localhost:2181(CONNECTED) 17] 

The log information output by the console is as follows:

2018-04-25 16:44:03,472 [main-EventThread] [org.zero01.zk.demo.ZKNodeAlterOperator.process(ZKNodeAlterOperator.java:58)] - [WARN] 接收到watch通知:WatchedEvent state:SyncConnected type:None path:null
修改节点:/testNode成功...
当前数据版本为:2
{'alter':'success'}

Deleting zk nodes synchronously/asynchronously

Similarly, there are two ways to delete a node: synchronous and asynchronous. In the operation of deleting a node, it is more user-friendly to use asynchronous, because there is a callback notification and a synchronous method, except for setting the watch event, otherwise there is no notification. Let's first take a look at the delete node of the synchronization method, the code is as follows:

package org.zero01.zk.demo;

import org.apache.zookeeper.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZKNodeDeleteOperator implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZKNodeDeleteOperator.class);

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private static ZooKeeper zooKeeper;

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    public static void main(String[] args) throws Exception {
        zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAlterOperator());
        // 创建节点
        zooKeeper.create("/testDeleteNode", "test-delete-data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        Thread.sleep(1000);
        /**
         * 删除节点(同步)
         * 参数:
         * path:需要删除的节点路径
         * version:数据版本
         */
        zooKeeper.delete("/testDeleteNode", 0);

        zooKeeper.close();
    }
}

Since the synchronous delete method does not have a return value, we cannot output the content to the console.

Then let's take a look at the asynchronous method of deleting nodes. First, we need to create a new class to implement the callback interface method:

package org.zero01.zk.demo;

import org.apache.zookeeper.AsyncCallback.VoidCallback;

public class DeleteCallBack implements VoidCallback {

    // 回调函数
    public void processResult(int rc, String path, Object ctx) {
        System.out.println("删除节点:" + path + " 成功...");
        System.out.println((String) ctx);
    }
}

Then modify the main method of the ZKNodeDeleteOperator class:

public class ZKNodeDeleteOperator implements Watcher {
    public static void main(String[] args) throws Exception {
        zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAlterOperator());
        // 创建节点
        zooKeeper.create("/testDeleteNode", "test-delete-data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        Thread.sleep(1000);
        /**
         * 删除节点(异步)
         * 参数:
         * path:需要删除的节点路径
         * version:数据版本
         * sc:实现回调函数的对象
         * ctx:给回调函数的上下文
         */
        String ctx = "{'delete':'success'}";
        zooKeeper.delete("/testDeleteNode", 0, new DeleteCallBack(), ctx);
        Thread.sleep(2000);
        zooKeeper.close();
    }
}

Running this class, the console output is as follows:

删除节点:/testDeleteNode 成功...
{'delete':'success'}

Get zk node data

The above sections have introduced the additions, deletions and changes, and now it is left to check. The same query also has two methods: synchronous and asynchronous. The asynchronous method has been introduced in the previous example of addition, deletion and modification. The use of asynchrony in the query is the same as the addition, deletion and modification, so we will not demonstrate the asynchrony of the query. There are three kinds of data in zk that can be queried: query zk node data, query the list of zk child nodes, and query whether a zk node exists. This section first introduces how to query zk node data.

Now on the zookeeper server, there is a /testNode node. The node data content is as follows:

[zk: localhost:2181(CONNECTED) 3] get /testNode
asynchronous-data
...
[zk: localhost:2181(CONNECTED) 4] 

Then we write a ZKGetNodeData class and call the zookeeper API to get the zk node data. Code example:

package org.zero01.zk.demo;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @program: zookeeper-connection
 * @description: 获取zk节点数据demo
 * @author: 01
 * @create: 2018-04-26 18:05
 **/
public class ZKGetNodeData implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(ZKGetNodeData.class);

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private static ZooKeeper zooKeeper;
    private static Stat stat = new Stat();

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
        logger.warn("接收到watch通知:{}", watchedEvent);
    }

    public static void main(String[] args) throws Exception {
        zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKGetNodeData());

        /**
         * 参数:
         * path:节点路径
         * watch:true或者false,注册一个watch事件
         * stat:状态,我们可以通过这个对象获取节点的状态信息
         */
        byte[] resByte = zooKeeper.getData("/testNode", true, stat);
        String result = new String(resByte);
        System.out.println("/testNode 节点的数据: " + result);

        zooKeeper.close();
    }
}

The console output is as follows:

/testNode 节点的值: asynchronous-data

By implementing the notification method of the Watcher interface and combining this API for obtaining node data, we can obtain the latest data when the data changes. In the following example, in the ZKGetNodeData class, add the following code:

...
public class ZKGetNodeData implements Watcher {
    ...
    // 计数器
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
        try {
            if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {
                ZooKeeper zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKGetNodeData());
                byte[] resByte = zooKeeper.getData("/testNode", false, stat);
                String result = new String(resByte);
                System.out.println("/testNode 节点的数据发生了变化");
                System.out.println("新的数据为: " + result);
                System.out.println("新的数据版本号为:" + stat.getVersion());

                // 通知完之后,计数器减一
                countDownLatch.countDown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        ...
        // 等待线程执行
        countDownLatch.await();
    }
}

At this time, since we called the await() method in main, the main thread will be blocked. Then we go to the zookeeper server and operate the data of the node, as follows:

[zk: localhost:2181(CONNECTED) 11] get /testNode
asynchronous-data
cZxid = 0x700000014
ctime = Wed Apr 25 22:17:26 CST 2018
mZxid = 0x800000011
mtime = Fri Apr 27 03:04:09 CST 2018
pZxid = 0x700000014
cversion = 0
dataVersion = 6
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 17
numChildren = 0
[zk: localhost:2181(CONNECTED) 12] set /testNode new-data 6       
cZxid = 0x700000014
ctime = Wed Apr 25 22:17:26 CST 2018
mZxid = 0x800000013
mtime = Fri Apr 27 03:04:35 CST 2018
pZxid = 0x700000014
cversion = 0
dataVersion = 7
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
[zk: localhost:2181(CONNECTED) 13]

When we modify the data, the console will output the following content, and the main thread will unblock and end the execution:

/testNode 节点的数据: asynchronous-data
/testNode 节点的数据发生了变化
新的数据为: new-data
新的数据版本号为:7

Get a list of zk child nodes

This section describes how to obtain the list of zk child nodes. There are also two methods: synchronous and asynchronous. The synchronous method is introduced here. There are three nodes under the testNode node, as follows:

[zk: localhost:2181(CONNECTED) 20] ls /testNode
[ThreeNode, TwoNode, OneNode]
[zk: localhost:2181(CONNECTED) 21] 

Let's write a demo to get the list of child nodes under this node. code show as below:

package org.zero01.zk.demo;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.util.List;

/**
 * @program: zookeeper-connection
 * @description:  zookeeper 获取子节点数据的demo演示
 * @author: 01
 * @create: 2018-04-26 21:13
 **/
public class ZKGetChildrenList implements Watcher{

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private static ZooKeeper zooKeeper;

    // Watch事件通知方法
    public void process(WatchedEvent watchedEvent) {
    }

    public static void main(String[] args) throws Exception {
        zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKGetChildrenList());

        /**
         * 参数:
         * path:父节点路径
         * watch:true或者false,注册一个watch事件
         */
        List<String> strChildList = zooKeeper.getChildren("/testNode", false);
        for (String s : strChildList) {
            System.out.println(s);
        }
    }
}

The console will output the following:

ThreeNode
TwoNode
OneNode

Determine whether the zk node exists

Finally, it introduces how to judge whether a zk node exists. There are also two methods: synchronous and asynchronous. The synchronous one is introduced here. Let's write a demo to determine whether a zk node exists. code show as below:

package org.zero01.zk.demo;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * @program: zookeeper-connection
 * @description: zookeeper 判断节点是否存在demo
 * @author: 01
 * @create: 2018-04-26 22:06
 **/
public class ZKNodeExist implements Watcher {

    // 集群模式则是多个ip
    private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181";
    // 超时时间
    private static final Integer timeout = 5000;
    private static ZooKeeper zooKeeper;

    public void process(WatchedEvent watchedEvent) {
    }

    public static void main(String[] args) throws Exception {
        zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeExist());

        /**
         * 参数:
         * path:节点路径
         * watch:true或者false,注册一个watch事件
         */
        Stat stat = zooKeeper.exists("/testNode", true);
        if (stat != null) {
            System.out.println("testNode 节点存在...");
            System.out.println("该节点的数据版本为:" + stat.getVersion());
        } else {
            System.out.println("该节点不存在...");
        }
    }
}

Running the class, the console output is as follows:

testNode 节点存在...
该节点的数据版本为:7

Replace testNode with a non-existent node, run the class, and the console output is as follows:

该节点不存在...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324979777&siteId=291194637