CuratorFramework 是Netflix公司开发一款连接zookeeper服务的框架,提供了比较全面的功能,除了基础的节点的操作,节点的监听,还有集群的连接以及重试。
首先是创建一个连接
RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
//通过工厂创建Curator
CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2184").sessionTimeoutMs(10000).retryPolicy(policy).build();
curator.start();
该方法配置重连retryPolicy以及回话有效时间sessionTimeoutMs,重连就是当客户端与zookeeper 连接异常的时候,如网络波动,断开链接,支持重新连接,会话有效这个与节点的属性有关。那么zookeeper 有哪些节点属性。
Zookeeper 有4种节点属性,持久化节点PERSISTENT,临时节点EPHEMERAL,持久化时序节点PERSISTENT_SEQUENTIAL,临时时序节点EPHEMERAL_SEQUENTIAL
。
持久化节点:一般通过curator.create().forPath("/PATH") 代码创建的节点默认是持久化节点,持久化节点就是不论链接是否断开以及回话是否失效,都不会删除
临时节点:
curator.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/PATH");
上面代码通过create时候指定创建的节点类型为临时节点,临时节点就是链接断开或者回话失效就是sessionTimeoutMs 配置的时间内,会话就失效了,那么该节点就删除了。例如上面代码指定的时间为10000毫秒,当10s 后会话失效创建的PATH节点自动删除。临时节点很有作用。例如当有一个主服务,多个备用服务,当主服务挂掉后,想启用备用服务,可以利用zookeeper 临时节点这个功能,当服务挂掉,zookeeper节点删除,通过节点监听功能,启用备用服务,而保证服务正常。
持久化时序节点:
curator.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/PATH");
这个和持久化代码的区别就是,当节点是创建了一个持久化节点PATH,然后在创建就会抛出一个节点已经存在的异常。 而当使用上面创建时序节点的代码,就会创建一个创建一个PATH0000000021的节点,而且可以创建多个。
临时持久化节点就不用说了,就是有时间限制的持久化时序节点。
一般使用的都是持久化节点和备用节点,时序节点很少使用。
CuratorFramework 节点的操作
curator.create().for("/PATH") // 创建节点
curator.getData().for("/PATH") // 获取节点数据
curator.setData().for("/PATH") // 节点赋值
curator.checkExist().for("/PATH") // 判断是否存在该节点
CuratorFramework 提供了节点的监听功能,当节点数据变化,修改,会调用注册监听事件。一般使用比较多的是两个监听事件NodeCacheListener和 PathChildrenCacheListener,监听事件需要通过创建节点缓存,然后在节点缓存里面添加监听事件。这两个监听事件的区别是第一个监听本节点,只能监听节点数据的变化,无法监听节点的删除,PathChildrenCacheListener监听的本节点的子节点的变化,包括数据修改以及节点的添加删除。
通过代码来了解下这两个监听器的使用
package com.client;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ClientSingleWatch {
public static void main(String[] args) throws Exception{
RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
//通过工厂创建Curator
CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
.sessionTimeoutMs(2000).retryPolicy(policy).build();
curator.start();
watchChild(curator, "/PATH");
watch(curator, "/PATH");
while(true){
}
}
//创建本节点数据变化监听事件
public static void watch(CuratorFramework curator, String path) throws Exception{
final NodeCache nodeCache = new NodeCache(curator, path, false);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("开始监听本级节点-----");
System.out.println("监听的节点为" + nodeCache.getCurrentData().getPath() + "数据变为 : "+new String(nodeCache.getCurrentData().getData()));
}
});
nodeCache.start();
}
//创建本节点的子节点监听事件
public static void watchChild(CuratorFramework curator, String path) throws Exception{
PathChildrenCache childrenCache = new PathChildrenCache(curator, path, true);
PathChildrenCacheListener childrenCacheListener = new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client,
PathChildrenCacheEvent event) throws Exception {
System.out.println("开始监听子节点:-----");
ChildData data = event.getData();
switch (event.getType()) {
case CHILD_ADDED:
System.out.println("CHILD_ADDED : "+ data.getPath() +" 数据:"+ data.getData());
break;
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED : "+ data.getPath() +" 数据:"+ data.getData());
break;
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED : "+ data.getPath() +" 数据:"+ new String(data.getData()));
break;
default:
break;
}
}
};
childrenCache.getListenable().addListener(childrenCacheListener);
System.out.println("Register zk watcher successfully!");
childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
}
}
上面代码两个方法watch 和 watchChild分别注册两个监听事件,第一个监听PATH本级节点数据变化,第二个监听了PATH 子级节点时候有新增删除修改。在main方法里面写了个死循环,保证持续监听。启动后在zookeeper 节点树上有一个PATH节点,这里说明下启动监听,如果不存在节点会创建一个没有数据的节点,启动后控制台输出如下,
Register zk watcher successfully!
开始监听子节点:-----
开始监听子节点:-----
开始监听本级节点-----
监听的节点为/PATH数据变为 :
然编写一个对节点进行修改删除的main方法
package com.client;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
public class ZookeeperClient4 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//
RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
//通过工厂创建Curator
CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2184")
.sessionTimeoutMs(10000).retryPolicy(policy).build();
curator.start();
curator.setData().forPath("/PATH", "333".getBytes());
curator.create().forPath("/PATH/TEST");
curator.setData().forPath("/PATH/TEST", "4444".getBytes());
curator.delete().forPath("/PATH/TEST");
}
}
启动这个main方法,
可以看到监听main方法输出了以下几行
开始监听本级节点-----
监听的节点为/PATH数据变为 : 333
开始监听子节点:-----
CHILD_ADDED : /PATH/TEST 数据:192.168.43.234
开始监听子节点:-----
CHILD_UPDATED : /PATH/TEST 数据:4444
开始监听子节点:-----
CHILD_REMOVED : /PATH/TEST 数据:4444
分析代码
curator.setData().forPath("/PATH", “333”.getBytes()); 这行代码向PATH节点添加输出,触发了监听本级节点方法,输出了”监听的节点为/PATH数据变为 : 333
”,
curator.create().forPath("/PATH/TEST"); 这行代码在PATH 下创建一个TEST 子节点,触发了监听PATH子节点的方法。该监听可以获取子节点的几种操作CHILD_ADDED,CHILD_REMOVED,CHILD_UPDATED,分别是节点新增,节点修改,节点删除,那么新增以后触发监听event的type类型为CHILD_ADDED,修改以后触发监听event的type类型为CHILD_UPDATED,删除以后触发监听event的type类型为CHILD_UPDATED,
到这,关于zookeeper所有节点相关操作都介绍完了,下节将介绍分布式环境下zookeeper节点监听,以及监听可以解决何种业务场景。