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