连接Zookeeper
重启创建zk1容器,将容器2181端口映射到本机
docker rm -f zk1
docker run -itd --name zk1 -p 2181:2181 -v ~/zkcluster/zk1/zoo.cfg:/conf/zoo.cfg -v ~/zkcluster/zk1/data:/data --network zknet --network-alias zk1 zookeeper
java端
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
</dependency>
在连接状态为 Event.KeeperState.SyncConnected
的时候表示连接成功,所以需要阻塞当前线程,当获取到Zookeeper实例时再释放。这里用 CountDownLatch
对主线程阻塞,在 process
方法中释放阻塞
public class ZkDemo1 {
public static void main(String[] args) {
try {
CountDownLatch countDownLatch = new CountDownLatch(1);
ZooKeeper zooKeeper = new ZooKeeper("192.168.159.129:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {
System.out.println("连接创建成功..");
countDownLatch.countDown();
}
}
});
countDownLatch.await();
// 在这之后可以对zookeeper进行操作
// ...
} catch (Exception e) {
e.printStackTrace();
}
}
}
创建节点
在创建节点时,可以自定义Acl,或者用已经预定义好的Acl
用默认的Acl创建节点,就像shell窗口 create /zknode
一样,默认的权限是 world:anyone:cdrwa
zooKeeper.create("/demo", "哈哈哈嗝".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
这行代码创建了 /demo
节点,值是 哈哈哈嗝
。ZooDefs.Ids.OPEN_ACL_UNSAFE
看源码可知是 world:anyone:cdrwa
,CreateMode.PERSISTENT
表示创建的是一个临时节点
追踪源码可以发现,create
方法传入的Acl只是一个 ArrayList<ACL>
。ACL
对象由 ZooDefs.Perms
和 Id
构成。
ZooDefs.Perms.ALL
表示 cdrwa
权限,只是把前面几种权限 |
了一下,可以发现,可以用同样的方式构建自定义权限,比如 ZooDefs.Perms.READ | ZooDefs.Perms.ADMIN
代表 ra
权限。
简单的把5种权限看成5位表示的二进制数 11111
就是 ZooDefs.Perms.ALL
,也就是31。10001
= 17
代表 ra
权限。规律也挺简单的。
来看个自定义权限的例子:
try {
ArrayList<ACL> acls = new ArrayList<>();
acls.add(new ACL(ZooDefs.Perms.READ | ZooDefs.Perms.ADMIN, ZooDefs.Ids.ANYONE_ID_UNSAFE));
zooKeeper.create("/demo", "哈哈哈嗝".getBytes(StandardCharsets.UTF_8), acls, CreateMode.PERSISTENT);
} catch (Exception e) {
e.printStackTrace();
}
创建了 /demo
节点,值为 哈哈哈嗝
。权限是 ra
查询节点
传入了三个参数
- path:节点路径
- watcher:监听器
- stat:元属性
try {
CountDownLatch countDownLatch = new CountDownLatch(1);
Stat stat = new Stat();
byte[] data = zooKeeper.getData("/demo", event -> {
// 打印事件类型
System.out.println("----------watch---------");
System.out.println(event.getType());
countDownLatch.countDown();
}, stat);
// 打印数据
System.out.println("----------data-----------");
System.out.println(new String(data, StandardCharsets.UTF_8));
// 获取元属性
System.out.println("----------stat-----------");
System.out.println(stat.getDataLength());
System.out.println(stat.getVersion());
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
打印了 /demo
的数据和元属性,并且传入一个监听器,一直到事件触发时程序才结束
修改 /demo
节点
触发了监听器事件
当然不需要监听和查看元属性,也可以设置为null
byte[] data = zooKeeper.getData("/demo", null, null);
修改节点数据
传入3个参数:
- path:节点路径
- data:节点新数据
- version:版本号,如果传
-1
,则视为不根据版本号修改
zookeeper.setData("/demo", "咯咯嗝".getBytes(StandardCharsets.UTF_8), -1);
删除节点
传入2个参数
- path:节点路径
- version:版本号
zooKeeper.delete("/zknode", -1);
如果 /zknode
还有子节点,删除失败。如果需要删除由子节点的节点,需要自己实现递归删除逻辑
查看所有子节点
名字不是以 /
开头的,如果需要查看子节点的子节点,需要在头部加上 /
List<String> children = zooKeeper.getChildren(path, false);
设置ACL
zooKeeper.setACL("/demo", ZooDefs.Ids.OPEN_ACL_UNSAFE, -1);