Curator
常用操作:创建连接
、添加节点
、删除节点
、修改节点
、查询节点
、Watch事件监听
首先还是创建项目所需要的环境
1、在IDEA中创建maven工程
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
2、创建连接
第一种方式创建连接
:
CuratorFramework client = CuratorFrameworkFactory.newClient(
"192.168.42.133:2181,192.168.42.134:2181",
60 * 1000,
15 * 1000,
retryPolicy
);
client.start();//开启连接
首先了解newClient()方法的四大参数的意义以及newClient()方法的原型
public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy) {
return builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).build();
}
String connectString
:连接字符串,zk server地址和端口
int sessionTimeoutMs
:会话超时时间 单位ms(连接建立
后,zookeeper的客户端
和服务端通信
时没连通超时)
int connectionTimeoutMs
:连接超时时间 单位ms
RetryPolicy retryPolicy
:重试策略
重试策略 | 含义解释 |
---|---|
ExponentialBackoffRetry | 多久重试一次,重试多少次(两个参数,多久,几次) |
RetryForever | 一直重试 |
RetryOneTime | 重试一次 |
RetryNTimes | 重试多次 |
运行结果:
2021-12-06 23:38:59,554 0 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:zookeeper.version=3.6.2--803c7f1a12f85978cb049af5e4ef23bd8b688715, built on 09/04/2020 12:44 GMT
2021-12-06 23:38:59,589 35 [ main] INFO org.apache.zookeeper.ZooKeeper - Client
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:java.io.tmpdir=C:\Users\ADMINI~1\AppData\Local\Temp\
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:java.compiler=<NA>
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.name=Windows 10
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.arch=amd64
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.version=10.0
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:user.name=Administrator
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:user.home=C:\Users\Administrator
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:user.dir=D:\zookeeper
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.memory.free=101MB
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.memory.max=1788MB
2021-12-06 23:38:59,590 36 [ main] INFO org.apache.zookeeper.ZooKeeper - Client environment:os.memory.total=121MB
2021-12-06 23:38:59,639 85 [ main] INFO work.imps.CuratorFrameworkImpl - Starting
2021-12-06 23:38:59,644 90 [ main] DEBUG curator.CuratorZookeeperClient - Starting
2021-12-06 23:38:59,644 90 [ main] DEBUG apache.curator.ConnectionState - Starting
2021-12-06 23:38:59,644 90 [ main] DEBUG apache.curator.ConnectionState - reset
2021-12-06 23:38:59,649 95 [ main] INFO org.apache.zookeeper.ZooKeeper - Initiating client connection, connectString=192.168.42.133:2181,192.168.42.134:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@5f9d02cb
2021-12-06 23:38:59,664 110 [ main] INFO ache.zookeeper.common.X509Util - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2021-12-06 23:39:00,474 920 [ main] INFO che.zookeeper.ClientCnxnSocket - jute.maxbuffer value is 1048575 Bytes
2021-12-06 23:39:00,494 940 [ main] INFO rg.apache.zookeeper.ClientCnxn - zookeeper.request.timeout value is 0. feature enabled=false
2021-12-06 23:39:00,507 953 [ main] INFO work.imps.CuratorFrameworkImpl - Default schema
第二种创建连接方式
:
CuratorFrameworkFactory client = CuratorFrameworkFactory.builder().connectString("192.168.42.133:2181,192.168.42.134:2181")
.sessionTimeoutMs(60*1000)
.connectionTimeoutMs(15*1000)
.retryPolicy(retryPolicy)
.namespace("temp")
.build();
client.start();
其中namespace("temp")
表示是每次在该temp目录下创建节点
单纯是从上面还是无法明显的效果,接下来我们开始创建些节点
3、添加节点
在添加节点前的zookeeper:
[zookeeper]
[zk: localhost:2181(CONNECTED) 14]
@Test
public void init() throws Exception {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,10);
CuratorFramework client = CuratorFrameworkFactory.newClient(
"192.168.42.133:2181,192.168.42.134:2181",
60 * 1000,
15 * 1000,
retryPolicy
);
client.start();//开启连接
String s = client.create().forPath("/abc", "1234".getBytes());
System.out.println(s);
}
}
执行完上面的代码,zookeeper的节点:
[zk: localhost:2181(CONNECTED) 14] ls /
[temp, zookeeper]
[zk: localhost:2181(CONNECTED) 15] get -s /temp
1234
cZxid = 0x800000011
ctime = Mon Dec 06 08:29:41 PST 2021
mZxid = 0x800000011
mtime = Mon Dec 06 08:29:41 PST 2021
pZxid = 0x800000011
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
如果创建节点,没有设置数据,就会把当前的IP设置为默认的值
在加上client.create().forPath("/abc");该代码的话,再获取/abc节点的值,发现是IP地址值
[zk: localhost:2181(CONNECTED) 18] get /abc
192.168.73.1
创建节点不是有两种:持久的
、临时的
以及是有序的
、无序的
,上面的创建都是默认是持久的节点
client.create().withMode(CreateMode.EPHEMERAL).forPath("/abc1");
withMode设置节点的类型,CreateMode是一个枚举类,如果是临时的,只要一次运行结束,再在zookeeper上查看还是无法看到的,一次会话结束节点就会删除
创建多级的节点
client.create().creatingParentContainersIfNeeded().forPath("/a/c/d","acd".getBytes());
总结创建节点:
基本操作 | 代码 |
---|---|
基本创建 | create().forPath("/abc") 默认的值是IP地址 |
创建节点带数据 | create().forPath("/abc",“acv”.getBytes()) |
设置节点的类型 | create().withMode(CreateMode.EPHEMERAL).forPath("") |
创建多级节点 | create().creatingParentContainersIfNeeded() .forPath("/a/c/d",“acd”.getBytes()); |
4、删除节点
分类 | 代码 |
---|---|
删除单个节点 | client.delete() .forPath("/temp") |
删除有子节点的节点 | client.delete().deletingChildrenIfNeeded() .forPath("/"); |
必须成功的删除 | client.delete().guaranteed().deletingChildrenIfNeeded() .forPath("/abc") |
删除带有回调函数 | client.delete().guaranteed().inBackground(new BackgroundCallback() |
4.1、删除单个节点
java代码:
@Test
public void TestDelete() throws Exception {
client.delete().forPath("/temp");
}
[zk: localhost:2181(CONNECTED) 1] ls /temp
[]
[zk: localhost:2181(CONNECTED) 2] get /temp
1234
[zk: localhost:2181(CONNECTED) 3] ls /
[a, abc, zookeeper]
4.2、删除有子节点的节点
java代码:
@Test
public void TestDeleteWithNode() throws Exception {
client.delete().deletingChildrenIfNeeded().forPath("/");
}
[zk: localhost:2181(CONNECTED) 3] ls /
[a, abc, zookeeper]
[zk: localhost:2181(CONNECTED) 4] ls /
[a, abc, zookeeper]
[zk: localhost:2181(CONNECTED) 5] ls /a
[c]
[zk: localhost:2181(CONNECTED) 6] ls /a/c
[d]
[zk: localhost:2181(CONNECTED) 7] ls /
[abc, zookeeper]
4.3、必须成功的删除
java代码:
@Test
public void TestDeleteguaranteed() throws Exception {
client.delete().guaranteed().deletingChildrenIfNeeded().forPath("/abc");
}
[zk: localhost:2181(CONNECTED) 8] ls /
[abc, zookeeper]
[zk: localhost:2181(CONNECTED) 9] ls /abc
[]
[zk: localhost:2181(CONNECTED) 10] ls /
[zookeeper]
4.3、必须成功的删除
java代码:
@Test
public void TestDeletebackFunction() throws Exception {
client.delete().guaranteed().inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println(curatorEvent);
}
}).forPath("/temp");
}
5、修改节点
比较简单:
client.setData().forPath("/a","abc3".getBytes());
但是有个问题就是如果多个对数据进行修改就会出现问题,这时需要修改之前需要查询版本号
:
// client是连接
Stat stat1 = new Stat();
client.getData().storingStatIn(stat1).forPath("/abc");
int version = stat1.getVersion();
client.setData().withVersion(version).forPath("/abc");
保证了原子性的操作
6、查询节点
查询节点 | get | 代码实现 |
---|---|---|
查询数据 | get | byte[] bytes = client.getData().forPath("/abc") ; System.out.println(bytes.toString()); |
查询子节点 | ls | List<String> list = client.getChildren().forPath("/"); |
查询节点状态信息 | ls -s | Stat stat = new Stat(); client.getData().storingStatIn(stat) .forPath("/a"); |
7、Watch事件监听
Zookeeper允许用户在指定节点
上注册一些Watcher
,并且在一些特定事件触发
的时候,Zookeeper服务端会将事件通知到响应的客户端,Zookeeper中引入了Wathcer机制来实现发布/订阅功能,能够让多个订阅者同时监听某一个对象(节点),当一个对象自身状态变化时,会通知所有订阅者。
Curator
引入了Cache来实现对Zookeeper服务器事件的监听
。
Zookeeper提供三种Watcher:
- NodeCache:
只是监听一个特定的节点
- PathChildrenCache:
监控
一个Node的所有子节点
- TreeCache:可以监控整个树上的所有节点,包括自己
7.1、NodeCache 监听一个节点
java代码:
@Test
public void TestWatch() throws Exception {
// 监听一个节点
// 1、创建NodeCache对象
final NodeCache nodeCache = new NodeCache(client,"/temp");
nodeCache.start(true);
// 2、注册监听
nodeCache.getListenable().addListener(new NodeCacheListener() {
public void nodeChanged() throws Exception {
System.out.println("节点变化了....");
byte[] data = nodeCache.getCurrentData().getData();
System.out.println(new String(data));
}
});
// 3、开启监听,如果设置为true,则是开启监听时加载缓存
// 程序结束就无效果
while (true){
}
}
监听事件发生后触发:new NodeCacheListener(){ }
输出信息:
2021-12-07 16:54:39,748 18770 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Got notification sessionid:0x4000107285d0001
2021-12-07 16:54:39,748 18770 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Got WatchedEvent state:SyncConnected type:NodeDataChanged path:/temp for sessionid 0x4000107285d0001
2021-12-07 16:54:39,761 18783 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x4000107285d0001, packet:: clientPath:/temp serverPath:/temp finished:false header:: 9,3 replyHeader:: 9,47244640267,0 request:: '/temp,T response:: s{47244640259,47244640267,1638867170774,1638867279705,3,0,0,0,6,0,47244640259}
2021-12-07 16:54:39,763 18785 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x4000107285d0001, packet:: clientPath:/temp serverPath:/temp finished:false header:: 10,4 replyHeader:: 10,47244640267,0 request:: '/temp,T response:: #313233343536,s{47244640259,47244640267,1638867170774,1638867279705,3,0,0,0,6,0,47244640259}
节点变化了....
123456
如果是删除的话,就无法获取数据会报错:
2021-12-07 16:57:39,430 20770 [ain-EventThread] ERROR mework.recipes.cache.NodeCache - Calling listener
java.lang.NullPointerException
7.2、PathChildrenCache 监听父节点的所有子节点
java代码:
@Test
public void TestPathChildren() throws Exception {
// 第三个参数是是否把数据缓存
PathChildrenCache path = new PathChildrenCache(client, "/a", true);
path.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
System.out.println("/a下的子节点变化了...");
System.out.println(event);
if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
System.out.println("子节点的数据发生更新");
System.out.println(event.getData().getData());
}
}
});
path.start(true);
while (true){
}
}
PathChildrenCache path = new PathChildrenCache(client, “/a”, true);
第二个参数:是路径父节点
第三个参数:是否把数据缓存
输出信息:
/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/b', stat=47244640271,47244640271,1638867926344,1638867926344,0,0,0,0,0,0,47244640271
, data=null}}
2021-12-07 17:20:28,088 1023 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:null serverPath:null finished:false header:: 6,4 replyHeader:: 6,47244640275,0 request:: '/a/b,F response:: ,s{47244640271,47244640271,1638867926344,1638867926344,0,0,0,0,0,0,47244640271}
2021-12-07 17:20:28,088 1023 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:/a/c serverPath:/a/c finished:false header:: 7,4 replyHeader:: 7,47244640275,0 request:: '/a/c,T response:: ,s{47244640272,47244640272,1638867928929,1638867928929,0,0,0,0,0,0,47244640272}
/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/c', stat=47244640272,47244640272,1638867928929,1638867928929,0,0,0,0,0,0,47244640272
, data=null}}
2021-12-07 17:20:28,089 1024 [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:/a/d serverPath:/a/d finished:false header:: 8,4 replyHeader:: 8,47244640275,0 request:: '/a/d,T response:: ,s{47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273}
/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/d', stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null}}
7.3、TreeCache 监听子节点或者父节点的信息变化
java代码:
@Test
public void TestWatchTreeCache() throws Exception {
TreeCache treeCache = new TreeCache(client, "/a");
treeCache.getListenable().addListener(new TreeCacheListener() {
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
System.out.println("treeCache:子节点或者父节点的监听");
System.out.println(event);
if(event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)){
System.out.println("子节点或者父节点数据更新了....");
System.out.println(new String(event.getData().getData()));
}
}
});
treeCache.start();
while (true){
}
}
后台输出的信息:
treeCache:子节点或者父节点的监听
TreeCacheEvent{type=NODE_ADDED, data=ChildData{path='/a/d', stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null}}
2021-12-07 17:30:18,815 2478 [ain-EventThread] DEBUG mework.recipes.cache.TreeCache - processResult: CuratorEventImpl{type=CHILDREN, resultCode=0, path='/a/d', name='null', children=[], context=null, stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null, watchedEvent=null, aclList=null}
2021-12-07 17:30:18,815 2478 [ain-EventThread] DEBUG mework.recipes.cache.TreeCache - publishEvent: TreeCacheEvent{type=INITIALIZED, data=null}
treeCache:子节点或者父节点的监听