文章目录
本文介绍zk客户端curator的使用,本文主要介绍Curator recipes的使用
官方文档传送门
官方文档Curator recipes
参考:http://www.throwable.club/2018/12/16/zookeeper-curator-usage/
参考书籍:《从Paxos到ZooKeeper 分布式一致性原理与实践》
1. Curator-recipes简介
官网传送门
Curator recipes 提供了一些高级特性,包括领导人选举,共享锁,路径缓存和观察者,分布式队列,分布式优先级队列等等。
pom
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
2. 事件监听
Zookeeper原生支持通过注册Watcher来进行事件监听,但是并不方便,反复开发者反复注册Watcher。Cache是Curator中对事件监听的包装,可以看作是对事件监听的本地缓存视图,能够自动为开发者处理反复注册监听。Curator提供了三种Watcher Cache来监听结点的变化。
Cache
类型 | 描述 |
---|---|
NodeCache | 尝试保留本地缓存的节点中的数据。此类将监视节点,响应更新/创建/删除事件,下拉数据等。您可以注册一个侦听器,当发生更改时,该侦听器将得到通知。 |
PathChildrenCache | 路径缓存用于监视ZNode。每当添加,更新或删除子项时,路径缓存都会更改其状态以包含当前子项集,子项数据和子项状态。Curator框架中的路径缓存由PathChildrenCache类提供。对路径的更改将传递到已注册的PathChildrenCacheListener实例。 |
TreeCache | 尝试保留本地缓存的ZK路径的所有子级中的所有数据。此类将监视ZK路径,响应更新/创建/删除事件,拉下数据,等等。您可以注册一个侦听器,当发生更改时它会得到通知。 |
2.1 NodeCache
用于监听数据节点的变更。尝试保留本地缓存的节点中的数据。此类将监视节点,响应更新/创建/删除事件,下拉数据等。您可以注册一个侦听器,当发生更改时,该侦听器将得到通知。
事例
/**
* NodeCache
*/
@Test
public void nodeCache() throws Exception {
String path = "/node-cache";
// 创建节点并赋值
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "sima".getBytes());
// 参数3:是否对数据进行压缩
final NodeCache cache = new NodeCache(client, path, false);
// 参数1:默认false,如果设置true代表第一次启动的时候从ZK上读取对应节点的数据内容
cache.start(true);
cache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
// getCurrentData()得到节点当前的状态
ChildData data = cache.getCurrentData();
if (null != data) {
System.out.println("节点数据更新:" + new String(data.getData()));
} else {
System.out.println("节点被删除");
}
}
});
// 更新数据
client.setData().forPath(path, "gang".getBytes());
Thread.sleep(1000);
// 删除节点
client.delete().deletingChildrenIfNeeded().forPath(path);
Thread.sleep(Integer.MAX_VALUE);
/* cache.close();
client.close();*/
}
使用完cache记得close()
控制台
2.2 PathChildrenCache
路径缓存用于监视数据节点的子节点的变化。每当添加,更新或删除子项时,路径缓存都会更改其状态以包含当前子项集,子项数据和子项状态。Curator框架中的路径缓存由PathChildrenCache类提供。对路径的更改将传递到已注册的PathChildrenCacheListener实例。
2.2.1 事例
/**
* PathChildrenCache
*/
@Test
public void pathChildrenCache() throws Exception {
String path = "/path-cache1";
// 参数3:缓存节点内容,如果设置true,那么客户端在接收到节点列表变更的同时,也能够获取节点的数据内容
// 参数4(可选):threadFactory和executorService可以使用单独的线程池来处理事件通知
PathChildrenCache cache = new PathChildrenCache(client, path, true);
// 启动模式:
// NORMAL: 初始化缓存数据为空
// BUILD_INITIAL_CACHE: 在start方法返回前,初始化获取每个子节点数据并缓存
// POST_INITIALIZED_EVENT: 在后台异步初始化数据完成后,会发送一个INITIALIZED初始化完成事件
cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
// 初始化
// case INITIALIZED:
// System.out.println("INITIALIZED," + event.getData().getPath());
// break;
// 添加子节点
case CHILD_ADDED:
System.out.println("CHILD_ADDED," + event.getData().getPath());
break;
// 子节点数据变更
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED," + event.getData().getPath());
break;
// 子节点删除
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED," + event.getData().getPath());
break;
default:
break;
}
}
});
// 创建节点
client.create().withMode(CreateMode.PERSISTENT).forPath(path);
Thread.sleep(1000);
// 创建子节点
client.create().withMode(CreateMode.PERSISTENT).forPath(path + "/z2");
Thread.sleep(1000);
// 删除子节点
client.delete().forPath(path + "/z2");
Thread.sleep(1000);
// 删除节点
client.delete().forPath(path);
Thread.sleep(Integer.MAX_VALUE);
}
注意
- curator无法对当前节点和二级子节点进行监听
- PathChildrenCache在调用start()方法时,有3种启动模式,分别为NORMAL,BUILD_INITIAL_CACHE,POST_INITIALIZED_EVENT
- POST_INITIALIZED_EVENT状态event.getData()返回值为null
控制台
2.2.1 带线程参数事例
/**
* PathChildrenCache--带线程池
*/
@Test
public void pathChildrenCacheWithThread() throws Exception {
String path = "/path-cache1";
ExecutorService ex = Executors.newFixedThreadPool(2);
// 参数3:缓存节点内容,如果设置true,那么客户端在接收到节点列表变更的同时,也能够获取节点的数据内容
// 参数4(可选):threadFactory和executorService可以使用单独的线程池来处理事件通知
PathChildrenCache cache = new PathChildrenCache(client, path, true, false, ex);
// 启动模式:
// NORMAL: 初始化缓存数据为空
// BUILD_INITIAL_CACHE: 在start方法返回前,初始化获取每个子节点数据并缓存
// POST_INITIALIZED_EVENT: 在后台异步初始化数据完成后,会发送一个INITIALIZED初始化完成事件
cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
// 初始化
case INITIALIZED:
System.out.println("INITIALIZED," + event.getData().getPath());
break;
// 添加子节点
case CHILD_ADDED:
System.out.println("CHILD_ADDED," + event.getData().getPath());
break;
// 子节点数据变更
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED," + event.getData().getPath());
break;
// 子节点删除
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED," + event.getData().getPath());
break;
default:
break;
}
}
});
// 创建节点
client.create().withMode(CreateMode.PERSISTENT).forPath(path);
Thread.sleep(1000);
// 创建子节点
client.create().withMode(CreateMode.PERSISTENT).forPath(path + "/z2");
Thread.sleep(1000);
// 删除子节点
client.delete().forPath(path + "/z2");
Thread.sleep(1000);
// 删除节点
client.delete().forPath(path);
Thread.sleep(Integer.MAX_VALUE);
}
2.3 TreeCache
监听路径下所有节点的变化,相当于NodeCache+PathChildrenCache,尝试保留本地缓存的ZK路径的所有子级中的所有数据。此类将监视ZK路径,响应更新/创建/删除事件,拉下数据,等等。您可以注册一个侦听器,当发生更改时它会得到通知。
事例
/**
* TreeCache
*/
@Test
public void TreeCache() throws Exception {
String path = "/tree-cache";
// 创建节点
client.create().creatingParentsIfNeeded().forPath(path);
TreeCache cache = new TreeCache(client, path);
TreeCacheListener listener = (client1, event) ->
System.out.println("事件类型:" + event.getType() +
",路径:" + (null != event.getData() ? event.getData().getPath() : null));
cache.getListenable().addListener(listener);
cache.start();
// 更新数据
client.setData().forPath(path, "1".getBytes());
Thread.sleep(1000);
// 更新数据
client.setData().forPath(path, "2".getBytes());
Thread.sleep(1000);
// 删除节点
client.delete().deletingChildrenIfNeeded().forPath(path);
Thread.sleep(1000 * 2);
cache.close();
client.close();
}
注意:TreeCache在调用start()的时候会回调TreeCacheListener实例一个TreeCacheEvent,而回调的TreeCacheEvent对象的Type为INITIALIZED,ChildData为null,此时event.getData().getPath()可能导致空指针异常,需要我们主动处理并避免这种情况
控制台
3. Curator recipes
官网传送门
Curator recipes 提供了一些高级特性,包括领导人选举,共享锁,路径缓存和观察者,分布式队列,分布式优先级队列等等。
源码地址
IT-CLOUD-ZOOKEEPER :zookeeper客户端Curator事例
项目推荐
IT-CLOUD :IT服务管理平台,集成基础服务,中间件服务,监控告警服务等。
IT-CLOUD-ACTIVITI6 :Activiti教程源码。博文在本CSDN Activiti系列中。
IT-CLOUD-ELASTICSEARCH :elasticsearch教程源码。博文在本CSDN elasticsearch系列中。
IT-CLOUD-KAFKA :spring整合kafka教程源码。博文在本CSDN kafka系列中。
IT-CLOUD-KAFKA-CLIENT :kafka client教程源码。博文在本CSDN kafka系列中。
IT-CLOUD-ZOOKEEPER :zookeeper客户端Curator事例。博文在本CSDN zookeeper系列中。开源项目,持续更新中,喜欢请 Star~