继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

zk-04-zookeeper客户端操作

黑桃SEVEN_PIG
关注TA
已关注
手记 46
粉丝 10
获赞 8

1、zkCli客户端操作

1.1 连接服务器

通过 sh zkCli.sh 命令连接 zookeeper 客户端服务器。
当出现 WatchedEvent state:SyncConnected type:None path:null 表示成功连接上了zookeeper服务器

[root@k8smaster bin]# pwd
/opt/zookeeper-3.5.5/bin
[root@k8smaster bin]# sh zkCli.sh
...
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] 

上面默认是连接本地的2181端口的zookeeper服务器,如果希望连接指定的 zookeeper 服务器,可以通过如下方式实现:
sh zkCli.sh -server ip:port

1.2 创建节点 create

create [-s] [-e] path [data] [acl]

其中,-s表示顺序节点,-e表示临时节点,acl访问控制列表。默认情况下,即不添加-s 或- e 参数的,创建的是持久节点。

[zk: localhost:2181(CONNECTED) 0] create /firstNode 123
Created /firstNode
[zk: localhost:2181(CONNECTED) 1] 

执行完上面的命令,就在 zookeeper 的根节点下创建了一个叫作 /firstNode 的节点,并且节点的数据内容是“123”。另外,create 命令的最后一个参数是acl ,它是用来进行权限控制的,缺省情况下,不做任何权限控制。

1.3 读取子节点 ls

使用 ls 命令,可以列出ZooKeeper指定节点下的所有子节点。当然,这个命令只能看到指定节点下第一级的所有子节点。
ls [-s] [-w] [-R] path
-s表示获取节点信息,包括时间戳、版本号、数据大小等信息。
-w 设置 Watch监听器
-R 递归显示
path 表示的是指定数据节点的节点路径。
执行如下命令:

[zk: localhost:2181(CONNECTED) 1] ls /
[firstNode, zookeeper]
[zk: localhost:2181(CONNECTED) 2] 

第一次部署的 ZooKeeper 集群,默认在根节点“/”下面有一个叫作 /zookeeper 的保留节点。

1.4 读取数据内容 get

get [-s] [-w] path

-s表示获取节点信息,包括时间戳、版本号、数据大小等信息。
-w 设置 Watch监听器

读取 /firstNode 的数据内容,-s表示获取节点信息,可以看到数据版本 dataVersion 为0。

[zk: localhost:2181(CONNECTED) 3] get /firstNode
123
[zk: localhost:2181(CONNECTED) 4] get -s /firstNode
123
cZxid = 0x60000000c
ctime = Mon Dec 21 15:11:06 CST 2020
mZxid = 0x60000000c
mtime = Mon Dec 21 15:11:06 CST 2020
pZxid = 0x60000000c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 5] 

1.5 更新 set

set [-s] [-v version] path data
-s表示节点为顺序节点,-v 指定版本号,data 就是要更新的新内容。
在 zookeeper 中 ,节点的数据是有版本概念的,这个参数用于指定本次更新操作是基于 ZNode 的哪一个数据版本进行的。

设置 /firstNode 节点数据 456,再次通过 get -s 查看节点信息,看到数据内容由 123 变成了 456,数据版本 dataVersion 为1。

[zk: localhost:2181(CONNECTED) 5] set /firstNode 456
[zk: localhost:2181(CONNECTED) 6] get -s /firstNode
456
cZxid = 0x60000000c
ctime = Mon Dec 21 15:11:06 CST 2020
mZxid = 0x60000000f
mtime = Mon Dec 21 15:20:08 CST 2020
pZxid = 0x60000000c
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 7] 

1.6 获取节点的访问控制列表 getAcl

getAcl [-s] [-w] path

-s表示获取节点信息,包括时间戳、版本号、数据大小等信息。
-w 设置 Watch监听器

[zk: localhost:2181(CONNECTED) 11] getAcl /firstNode
'world,'anyone
: cdrwa
[zk: localhost:2181(CONNECTED) 12] getAcl -s /firstNode
'world,'anyone
: cdrwa
cZxid = 0x60000000c
ctime = Mon Dec 21 15:11:06 CST 2020
mZxid = 0x60000000f
mtime = Mon Dec 21 15:20:08 CST 2020
pZxid = 0x60000000c
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 13] 

上面 : cdrwa 表示权限控制列表

  • c(CREATE) : 创建子节点的权限。
  • r(READ) : 获取节点数据和子节点列表的权限。
  • w(WRITE) : 更新节点数据的权限。
  • d(DELETE) : 删除子节点的权限。
  • a(ADMIN) : 设置节点 ACL 的权限。

1.7 设置节点的访问控制列表 setAcl

setAcl [-s] [-v version] [-R] path acl

-s表述顺序节点,-v指定版本号,-R递归设置,acl权限列表。

1.8 删除节点 delete

delete [-v version] path

删除某一节点,只能删除无子节点的节点。-v 表示节点版本号

[zk: localhost:2181(CONNECTED) 40] create /firstNode1/nodeB cde
Created /firstNode1/nodeB
[zk: localhost:2181(CONNECTED) 41] create /firstNode1/nodeC fgh
Created /firstNode1/nodeC
[zk: localhost:2181(CONNECTED) 42] ls -R /firstNode1
/firstNode1
/firstNode1/nodeA
/firstNode1/nodeB
/firstNode1/nodeC
[zk: localhost:2181(CONNECTED) 43] 

删除 /firstNode1/nodeC

[zk: localhost:2181(CONNECTED) 43] delete /firstNode1/nodeC
[zk: localhost:2181(CONNECTED) 44] ls -R /firstNode1
/firstNode1
/firstNode1/nodeA
/firstNode1/nodeB
[zk: localhost:2181(CONNECTED) 45] 

1.9 删除所有 deleteall

deleteall path
递归的删除某一节点及其子节点

删除 /firstNode1 及其子节点

[zk: localhost:2181(CONNECTED) 47] ls -R /firstNode1
/firstNode1
/firstNode1/nodeA
/firstNode1/nodeB
[zk: localhost:2181(CONNECTED) 48] deleteall /firstNode1
[zk: localhost:2181(CONNECTED) 49] ls -R /firstNode1
Node does not exist: /firstNode1
[zk: localhost:2181(CONNECTED) 50] 

2、Java客户端API使用

引入 zookeeper Java客户端maven依赖

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

2.1 创建会话

通过创建ZooKeeper实例连接 zookeeper 服务器。

ZooKeeper的4种构造器源码


    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) throws IOException {
        this(connectString, sessionTimeout, watcher, false);
    }

    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, ZKClientConfig conf) throws IOException {
        this(connectString, sessionTimeout, watcher, false, conf);
    }

    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider) throws IOException {
        this(connectString, sessionTimeout, watcher, canBeReadOnly, aHostProvider, (ZKClientConfig)null);
    }

    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider, ZKClientConfig clientConfig) throws IOException {
...
    }

参数说明

  • connectString:指 ZooKeeper 服务器列表,由英文状态逗号分开的 host:port 字符串组成。

  • sessionTimeout:指会话的超时时间,是一个以“毫秒”为单位的整型值。

  • watcher:ZooKeeper允许客户端在构造方法中传入一个接口 Watcher 的实现类对象来作为默认的W atcher事件通知处理器。当然,该参数可以设置为 null 以表明不需要设置默认的 Watcher 处理器。

  • canBeReadOnly:这是一个boolean类型的参数,用于标识当前会话是否支持“read-only (只读) ” 模式。默认情况下,在ZooK eeper集群中,一个机器如果和集群中过半及以上机器失去了网络连接,那么这个机器将不再处理客户端请求(包括读写请求)。但是在某些使用场景下,当 ZooKeeper 服务器发生此类故障的时候,我们还是希望 ZooKeeper 服务器能够提供读服务(当然写服务肯定无法提供)一一这就是 ZooKeeper 的 “read-only” 模式。

  • ZKClientConfig :配置zookeeper连接的一些相关属性

  • HostProvider : HostProvider类定义了一个客户端的服务器地址管理器

创建一个 zookeeper 连接

public class ZkConnect implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        // 创建一个最基本的ZooKeeper对象实例
        ZooKeeper zookeeper = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkConnect());
        System.out.println("当前zookeeper状态:" + zookeeper.getState());
        try {
            //阻塞,直到countdown计数等于0
            countDownLatch.await();
        } catch (InterruptedException e) {
        }
        System.out.println("zookeeper 会话建立");
    }

    public void process(WatchedEvent event) {
        System.out.println("接收到监听事件:" + event);
        if (Event.KeeperState.SyncConnected == event.getState()) {
            // 倒数,计数-1
            countDownLatch.countDown();
        }
    }
}

运行结果:

当前zookeeper状态:CONNECTING
接收到监听事件:WatchedEvent state:SyncConnected type:None path:null
zookeeper 会话建立

2.2 创建节点

客户端可以通过ZooKeeper的 API 来创建一个数据节点,有如下两个方法,分別以同步和异步方式创建节点:

    // 同步创建节点
    public String create(final String path, byte data[], List<ACL> acl, CreateMode createMode);
    
    // 异步创建节点 
    public void create(final String path, byte data[], List<ACL> acl, CreateMode createMode, StringCallback cb, Object ctx)

参数说明

  • path : 需要戗建的数据节点的节点路径,例如, /zk-book/foo

  • data[] : 一个字节数组,是节点创建后的初始内容

  • acl : 节点的 ACL 策略

  • createMode : 节点类型,是一个枚举类型,通常有4 种可选的节点类型:
    • 持久(PERSISTENT)
    • 持久顺序(PERSISTENT_SEQUENTIAL)
    • 临时(EPHEMERAL)
    • 临时顺序(EPHEMERAL_SEQUENTIAL)

  • cb : 异步回调函数,需要实现StringCallback接口,当服务端节点创建完毕后,Zookeeper 客户端就会自动调用这个方法可以处理相关的业务逻辑了

  • ctx : 用于传递一个对象,可以在回调方法执行的时候使用,通常是放一个上下文(Context)信息。

注意:,无论是同步还是异步接口,ZooKeeper都不支持递归创建,即无法在父节点不存在的情况下创建一个子节点。另外,如果一个节点已经存在了,那么创建同名节点的时候,会抛出 NodeExistsException 异常。

同步创建临时节点和临时顺序节点

public class ZkCreateSync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        // 创建一个最基本的ZooKeeper对象实例
        ZooKeeper zookeeper = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkCreateSync());// 注册Watcher
        System.out.println("当前zookeeper状态:" + zookeeper.getState());
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        System.out.println("zookeeper 会话建立");
        String path1 = zookeeper.create("/zk-test-ephemeral-",// 节点路径
                // 节点数据
                "1111".getBytes(),
                // 对这个节点的任何操作都不受权限控制
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                // 临时节点
                CreateMode.EPHEMERAL);
        System.out.println("Success create znode: " + path1);

        String path2 = zookeeper.create("/zk-test-ephemeral-",//节点路径
                // 节点数据
                "2222".getBytes(),
                // 对这个节点的任何操作都不受权限控制
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                // 临时有序节点
                CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("Success create znode: " + path2);
    }

    public void process(WatchedEvent event) {
        System.out.println("接收到监听事件:" + event);
        if (Event.KeeperState.SyncConnected == event.getState()) {
            // 倒数,计数-1
            countDownLatch.countDown();
        }
    }
}

运行结果:

当前zookeeper状态:CONNECTING
接收到监听事件:WatchedEvent state:SyncConnected type:None path:null
zookeeper 会话建立
Success create znode: /zk-test-ephemeral-
Success create znode: /zk-test-ephemeral-0000000005

异步创建节点

public class ZkCreateASync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        // 创建一个最基本的ZooKeeper对象实例
        ZooKeeper zookeeper = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkCreateASync());// 注册Watcher
        System.out.println("当前zookeeper状态:" + zookeeper.getState());
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        System.out.println("zookeeper 会话建立");

        zookeeper.create("/zk-test-ephemeral-", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,
                new IStringCallback(), "I am context.");

        zookeeper.create("/zk-test-ephemeral-", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,
                new IStringCallback(), "I am context.");

        zookeeper.create("/zk-test-ephemeral-", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL,
                new IStringCallback(), "I am context.");
        Thread.sleep( Integer.MAX_VALUE );
    }

    public void process(WatchedEvent event) {
        System.out.println("接收到监听事件:" + event);
        if (Event.KeeperState.SyncConnected == event.getState()) {
            // 倒数,计数-1
            countDownLatch.countDown();
        }
    }
}

/**
 * 回调
 */
class IStringCallback implements AsyncCallback.StringCallback {
    /**
     * 创建结果回调
     *
     * @param rc   服务端响应码 ,
     *             0 (Ok):接口调用成功;
     *             -4 (ConnectionLoss) : 客户端和服务端连接已断开;
     *             -110 (NodeExists) : 指定节点已存在
     *             112 (SessionExpired) : 会话已过期
     * @param path 接口调用时传入API的数据节点的节点路径参数值
     * @param ctx  接口调用时传入API的Ctx参数值
     * @param name 实际路径,如果不是顺序节点则 path和name一样
     */
    public void processResult(int rc, String path, Object ctx, String name) {
        System.out.println("Create path result: [" + rc + ", " + path + ", "
                + ctx + ", real path name: " + name);
    }
}

运行结果:

当前zookeeper状态:CONNECTING
接收到监听事件:WatchedEvent state:SyncConnected type:None path:null
zookeeper 会话建立
Create path result: [0, /zk-test-ephemeral-, I am context., real path name: /zk-test-ephemeral-
Create path result: [-110, /zk-test-ephemeral-, I am context., real path name: null
Create path result: [0, /zk-test-ephemeral-, I am context., real path name: /zk-test-ephemeral-0000000007

2.3 删除节点

客户端可以通过ZooKeeper的 API 来创建一个数据节点,有如下两个方法,分別以同步和异步方式删除节点:

//同步删除
public void delete(final String path, int version);

//异步删除
public void delete(final String path, int version, VoidCallback cb, Object ctx)

参数说明

  • path : 指定数据节点的节点路径,即 API 调用的目的是删除该节点
  • version : 指定节点的数据版本,即表明本次删除操作是针对该数据版本进行的,-1 表示基于数据的最新版本进行
  • cb : 注册一个异步回调函数
  • ctx : 用于传递上下文信息的对象

如果版本号是-1,就是告诉ZooKeeper服务器,客户端需要基于数据的最新版本进行更新操作。

删除节点

public class ZkDeleteSync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        // 创建一个最基本的ZooKeeper对象实例
        ZooKeeper zookeeper = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkDeleteSync());// 注册Watcher
        System.out.println("当前zookeeper状态:" + zookeeper.getState());
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        System.out.println("zookeeper 会话建立");
        String path = "/zk-del";
        path = zookeeper.create(path, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        System.out.println("建立临时节点: " + path);
        // 如果版本号是-1,就是告诉ZooKeeper服务器,客户端需要基于数据的最新版本进行更新操作 
        zookeeper.delete(path, -1);
        System.out.println("删除临时节点: " + path);
    }

    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}

运行结果:

当前zookeeper状态:CONNECTING
zookeeper 会话建立
建立临时节点: /zk-del
删除临时节点: /zk-del

2.4 读取数据: 子节点列表

客户端可以通过ZooKeeper的 API 来获取一个节点的所有子节点,有如下方法:

public List<String> getChildren(String path, boolean watch);
public void getChildren(final String path, Watcher watcher, ChildrenCallback cb, Object ctx);
public void getChildren(String path, boolean watch, ChildrenCallback cb, Object ctx);
public void getChildren(String path, boolean watch, Children2Callback cb, Object ctx);
public List<String> getChildren(String path, boolean watch, Stat stat);
public List<String> getChildren(final String path, Watcher watcher);
public void getChildren(final String path, Watcher watcher, ChildrenCallback cb, Object ctx);
public List<String> getChildren(final String path, Watcher watcher, Stat stat);

参数说明

  • path : 指定数据节点的节点路径,即 API 调用的该节点的子节点列表
  • watcher : 注册的 Watcher,一 旦在本次子节点获取之后,子节点列表发生变更的话,那么就会向客户端发送通知。该参数允许传入null。
  • watch : 表明是否需要注册一个Watcher,如果这个参数是true, 那么ZooKeeper客户端会自动使用创建zookeeper实例时的那个默认Watcher;如果是false,表明不需要注册Watcher。
  • cb : 注册一个异步回调函数
  • ctx : 用于传递上下文信息的对象
  • stat : 指定数据节点的节点状态信息。用法是在接口中传入一个旧的 stat 变量,该 stat 变量会在方法执行过程中,被来自服务端响应的新 stat 对象替换。

同步获取子节点列表

public class ZkGetChildrenSync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkGetChildrenSync());// 注册默认的Watcher事件通知处理器
        System.out.println("当前zookeeper状态:" + zk.getState());
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        System.out.println("zookeeper 会话建立");
        String path = "/zk-parent";
        zk.create(path, "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        // 创建子节点
        zk.create(path + "/c1", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

        List<String> childrenList = zk.getChildren(path, true);
        // 子节点列表
        System.out.println("子节点列表" + childrenList);

        zk.create(path + "/c2", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        zk.create(path + "/c4", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        childrenList = zk.getChildren(path, true);
        System.out.println("子节点列表" + childrenList);
        Thread.sleep(Integer.MAX_VALUE);
    }

    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}

运行结果:

当前zookeeper状态:CONNECTING
zookeeper 会话建立
子节点列表[c1]
子节点列表[c4, c1, c2]

异步获取子节点列表

public class ZkGetChildrenASync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkGetChildrenASync());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-parent-async";
        zk.create(path, "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        zk.create(path+"/c1", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

        zk.getChildren(path, true, new IChildren2Callback(), null);

        zk.create(path+"/c2", "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

        Thread.sleep( Integer.MAX_VALUE );
    }

    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}

class IChildren2Callback implements AsyncCallback.Children2Callback{
    public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {
        System.out.println("Get Children znode result: [response code: " + rc + ", param path: " + path
                + ", ctx: " + ctx + ", children list: " + children + ", stat: " + stat);
    }
}

运行结果:

Get Children znode result: [response code: 0, param path: /zk-parent-async, ctx: null, children list: [c1], stat: 55834574861,55834574861,1608566226633,1608566226633,0,1,0,0,0,1,55834574862

2.5 读取数据: 节点数据内容

public void getData(String path, boolean watch, DataCallback cb, Object ctx);
public byte[] getData(String path, boolean watch, Stat stat);
public void getData(final String path, Watcher watcher, DataCallback cb, Object ctx);
public byte[] getData(final String path, Watcher watcher, Stat stat)

参数说明

  • path : 指定数据节点的节点路径,即 API 调用的是该节点的数据内容
  • watcher : 注册的 Watcher,一 旦在本次子节点获取之后,子节点列表发生变更的话,那么就会向客户端发送通知。该参数允许传入null。
  • watch : 表明是否需要注册一个Watcher,如果这个参数是true, 那么ZooKeeper客户端会自动使用创建zookeeper实例时的那个默认Watcher;如果是false,表明不需要注册Watcher。
  • cb : 注册一个异步回调函数
  • ctx : 用于传递上下文信息的对象
  • stat : 指定数据节点的节点状态信息。用法是在接口中传入一个旧的 stat 变量,该 stat 变量会在方法执行过程中,被来自服务端响应的新 stat 对象替换。

同步获取节点数据

public class ZkGetDataSync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkGetDataSync());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-sync";
        zk.create(path, "12".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

        System.out.println(new String(zk.getData(path, true, stat)));

        Thread.sleep(Integer.MAX_VALUE);
    }

    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            } else if (event.getType() == Event.EventType.NodeDataChanged) {
                try {
                    System.out.println(new String(zk.getData(event.getPath(), true, stat)));
                    System.out.println(stat.getCzxid() + "," +
                            stat.getMzxid() + "," +
                            stat.getVersion());
                } catch (Exception e) {
                }
            }
        }
    }
}

运行结果:

12

异步读取节点数据

public class ZkGetDataASync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkGetDataASync());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-async";
        zk.create( path, "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL );

        zk.getData( path, true, new IDataCallback(), null );

        Thread.sleep(Integer.MAX_VALUE);
    }

    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}


class IDataCallback implements AsyncCallback.DataCallback{
    public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
        System.out.println(rc + ", " + path + ", " + new String(data));
        System.out.println(stat.getCzxid()+","+
                stat.getMzxid()+","+
                stat.getVersion());
    }
}

运行结果:

0, /zk-async, 123
55834574890,55834574890,0

2.6 更新数据

// 同步设置数据
public Stat setData(final String path, byte data[], int version);
// 异步设置数据
public void setData(final String path, byte data[], int version, StatCallback cb, Object ctx);

参数说明

  • path : 指定数据节点的节点路径,即 API 调用的是该节点的数据内容
  • data[] : 一个字节数组,设置的节点数据内容
  • version : 指定节点的数据版本,即表明本次删除操作是针对该数据版本进行的,-1 表示基于数据的最新版本进行
  • cb : 注册一个异步回调函数
  • ctx : 用于传递上下文信息的对象

同步更新数据

public class ZkSetDataSync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkSetDataSync());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-sync";
        zk.create(path, "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        System.out.println("getData: " + new String(zk.getData(path, true, stat)));
        System.out.println(stat.getCzxid() + "," +
                stat.getMzxid() + "," +
                stat.getVersion());
        // 如果版本号是-1,就是告诉ZooKeeper服务器,客户端需要基于数据的最新版本进行更新操作
        stat = zk.setData(path, "456".getBytes(), -1);
        System.out.println(stat.getCzxid() + "," +
                stat.getMzxid() + "," +
                stat.getVersion());
        System.out.println("getData: " + new String(zk.getData(path, true, stat)));

        // 获取 stat 对应版本的数据
        stat = zk.setData(path, "789".getBytes(), stat.getVersion());
        System.out.println(stat.getCzxid() + "," +
                stat.getMzxid() + "," +
                stat.getVersion());
        System.out.println("getData: " + new String(zk.getData(path, true, stat)));
        try {
            zk.setData(path, "000".getBytes(), stat.getVersion());
        } catch (KeeperException e) {
            System.out.println("Error: " + e.code() + "," + e.getMessage());
        }
        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}

运行结果:

getData: 123
64424509501,64424509501,0
64424509501,64424509502,1
getData: 456
64424509501,64424509503,2
getData: 789

异步设置数据

public class ZkSetDataASync implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkSetDataASync());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-async";

        zk.create(path, "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        zk.setData(path, "456".getBytes(), -1, new IStatCallback(), null);
        System.out.println("getData: " + new String(zk.getData(path, true, stat)));

        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent event) {
        if (Event.KeeperState.SyncConnected == event.getState()) {
            if (Event.EventType.None == event.getType() && null == event.getPath()) {
                countDownLatch.countDown();
            }
        }
    }
}

class IStatCallback implements AsyncCallback.StatCallback {
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        if (rc == 0) {
            System.out.println("SUCCESS");
        }
    }
}

运行结果:

SUCCESS
getData: 456

2.7 检测节点是否存在

检测节点是否存在的方法如下:

// 同步检测,如果节点不存在,则返回null
public Stat exists(String path, boolean watch);
// 异步检测节点是否存在
public void exists(String path, boolean watch, StatCallback cb, Object ctx);
// 同步检测,如果节点不存在,则返回null
public Stat exists(final String path, Watcher watcher);
// 异步检测节点是否存在
public void exists(final String path, Watcher watcher, StatCallback cb, Object ctx);

参数说明

  • path : 指定数据节点的节点路径,即 API 调用的目的是检测该节点是否存在
  • watcher : 注册的 Watcher,用于监听三类事件:节点被创建;节点被删除;节点被更新;
  • watch : 指定是否复用ZooKeeper中默认的Watcher。
  • cb : 注册一个异步回调函数
  • ctx : 用于传递上下文信息的对象

同步监听

public class ZkExist implements Watcher {

    //倒数门闩,计数为1
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zk = null;

    public static void main(String[] args) throws Exception {
        zk = new ZooKeeper("k8smaster:2181",//zookeeper服务器
                5000, //会话超时时间
                new ZkExist());// 注册Watcher
        //阻塞,直到countdown计数等于0
        countDownLatch.await();
        String path = "/zk-sync";

        // 同步检测,如果节点不存在,则返回null,并对该 path 进行事件监听
        Stat stat = zk.exists(path, true);
        if (stat != null) {
            System.out.println(stat.getCzxid() + "," +
                    stat.getMzxid() + "," +
                    stat.getVersion());
        } else {
            System.out.println("节点:" + path + " 不存在");
        }

        zk.create(path, "aaa".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        zk.setData(path, "123".getBytes(), -1);

        zk.create(path + "/c1", "bbb".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        zk.delete(path + "/c1", -1);

        zk.delete(path, -1);

        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent event) {
        try {
            if (Event.KeeperState.SyncConnected == event.getState()) {
                if (Event.EventType.None == event.getType() && null == event.getPath()) {
                    countDownLatch.countDown();
                } else if (Event.EventType.NodeCreated == event.getType()) {
                    System.out.println("Node(" + event.getPath() + ")Created");
                    zk.exists(event.getPath(), true);
                } else if (Event.EventType.NodeDeleted == event.getType()) {
                    System.out.println("Node(" + event.getPath() + ")Deleted");
                    zk.exists(event.getPath(), true);
                } else if (Event.EventType.NodeDataChanged == event.getType()) {
                    System.out.println("Node(" + event.getPath() + ")DataChanged");
                    zk.exists(event.getPath(), true);
                }
            }
        } catch (Exception e) {
        }
    }
}

运行结果:

节点:/zk-sync 不存在
Node(/zk-sync)Created
Node(/zk-sync)DataChanged
Node(/zk-sync)Deleted
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP