ZooKeeper客户端Curator(监听篇)

10 篇文章 0 订阅
maven依赖


<dependency>


            <groupId>org.apache.curator</groupId>


            <artifactId>curator-recipes</artifactId>


            <version>2.8.0</version>   


        </dependency>


Path Cache


Path Cache用来监控一个ZNode的子节点. 当一个子节点增加, 更新,删除时, Path Cache会改变它的状态, 会包含最新的子节点, 子节点的数据和状态。(此处需要注意,他只会监听一级子节点,不会循环监听子节点下面的child)


实际使用时会涉及到四个类:


PathChildrenCache


PathChildrenCacheEvent


PathChildrenCacheListener


ChildData


创建Path Cache


通过下面的构造函数创建Path Cache:


public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, final ExecutorService executorService)
想使用cache,必须调用它的start方法,不用之后调用close方法。
start有两个, 其中一个可以传入StartMode,用来为初始的cache设置暖场方式(warm):


个人建议使用此构造方法,ExecutorService使用自己构建的线程池,保证线程可控


添加监控节点状态


添加监控节点状态的改变的Listener时,建议使用此方法,手动传入我们构建的线程池,保证线程可控。


childrenCache.getListenable().(T listener, Executor executor);
为什么要自己传入线程池呢?看下图和源码


 public PathChildrenCache(CuratorFramework client, String path, boolean cacheData)
    {
        this(client, path, cacheData, false, new CloseableExecutorService(Executors.newSingleThreadExecutor(defaultThreadFactory), true));
    }
 public void addListener(T listener)
    {
        addListener(listener, MoreExecutors.sameThreadExecutor());
    }




因为在zk丢失链接的时候,默认不传线程池的方法,在每次重连时都会会新new 出来一个线程池,线程一直处于活跃状态,如果zk服务端长时间未能恢复,会导致客户端现成打满


设置/更新、移除


设置/更新、移除其实是使用client (CuratorFramework)来操作, 不通过PathChildrenCache操作:


client.setData().forPath(path, bytes);
client.create().creatingParentsIfNeeded().forPath(path, bytes);
client.delete().forPath(path);
而查询缓存使用下面的方法:


for (ChildData data : cache.getCurrentData()) {
    System.out.println(data.getPath() + " = " + new String(data.getData()));
}
最后附上一段完整的代码


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.retry.ExponentialBackoffRetry;


/**
 * ZKClient
 * 
 * @author jiangzhixiong
 * @email xingxuan_jzx@foxmail.com
 * @date 2015年10月12日 下午5:18:21
 */
public class ChildPathZkClient {
// ip和端口url
private String url;
// 需要监听的base path
private String basePath;


private static CuratorFramework client = null;
private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 100, 5l, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100), new ThreadPoolExecutor.CallerRunsPolicy());


public void init() throws Throwable {
if (basePath == null) {
basePath = "o2o/zk/cache";
}
client = CuratorFrameworkFactory.builder().namespace(basePath).connectString(url).sessionTimeoutMs(5000).connectionTimeoutMs(3000).retryPolicy(new ExponentialBackoffRetry(1000, 0)).build();
client.start();
/**
* 监听子节点的变化情况
*/
watchChild("/");
}


protected static void watchChild(String path) throws Exception {
PathChildrenCache childrenCache = new PathChildrenCache(client, path, true, false, executor);
ZkPathListener listener = new ZkPathListener();
listener.setPathChildrenCache(childrenCache);
childrenCache.getListenable().addListener(listener, executor);
childrenCache.start();
}


public String getUrl() {
return url;
}


public void setUrl(String url) {
this.url = url;
}


public String getBasePath() {
return basePath;
}


public void setBasePath(String basePath) {
this.basePath = basePath;
}


public static void main(String[] args) throws Throwable {
CountDownLatch latch = new CountDownLatch(1);
client = CuratorFrameworkFactory.builder().namespace("o2o/zk/cache").connectString("192.168.200.98:2181").sessionTimeoutMs(5000).connectionTimeoutMs(3000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
client.start();


/**
* 监听子节点的变化情况
*/
watchChild("/");
latch.await();
}


}
import java.util.Map;


import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;


import com.jd.o2o.web.product.constants.zk.ZkSwitchEnum;
import com.jd.o2o.web.product.constants.zk.ZkValueEnum;
import com.jd.o2o.zk.cache.serializer.ZooKeeperSerializer;
import com.jd.o2o.zk.cache.serializer.impl.JdkSerializationZooKeeperSerializer;


/**
 * ZK监听器
 * 
 * @author jiangzhixiong
 * @email xingxuan_jzx@foxmail.com
 * @date 2015年10月12日 下午5:18:38
 */
public class ZkPathListener implements PathChildrenCacheListener {
private final Logger logger = LogManager.getLogger(ZkPathListener .class);
private final ZooKeeperSerializer<?> defaultSerializer = new JdkSerializationZooKeeperSerializer();
private PathChildrenCache pathChildrenCache;


@Override
public void childEvent(CuratorFramework paramCuratorFramework, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
// TODO
System.out.println(defaultSerializer.deserialize(event.getData().getData()));
break;
case CHILD_UPDATED:
// TODO
System.out.println(defaultSerializer.deserialize(event.getData().getData()));
break;
case CHILD_REMOVED:
// TODO
System.out.println(defaultSerializer.deserialize(event.getData().getData()));
break;
default:
break;
}
}
}








Node Cache


Node Cache用来监控一个ZNode. 当节点的数据修改或者删除时,Node Cache能更新它的状态包含最新的改变。


涉及到下面的三个类:


NodeCache


NodeCacheListener


ChildData


构建NodeCache






 public NodeCache(CuratorFramework client, String path)
想使用cache,依然要调用它的start方法,不用之后调用close方法。






添加监控节点状态


添加监控节点状态的改变的Listener时,建议使用此方法,手动传入我们构建的线程池,保证线程可控。


NodeCache.getListenable().(T listener, Executor executor);
同样附一段完整的代码


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;


/**
 * ZK链接
 * 
 * @author jiangzhixiong
 * @email xingxuan_jzx@foxmail.com
 * @date 2015年10月12日 下午5:18:21
 */
public class ZkNodeClient {
// ip和端口url
private String url;
// 需要监听的base path
private String basePath;
        private static NodeCache nodeCache;
private static CuratorFramework client = null;
private final static ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();


public void init() throws Throwable {
if (basePath == null) {
basePath = "o2o/zk/cache";
}
client = CuratorFrameworkFactory.builder().namespace(basePath).connectString(url).sessionTimeoutMs(5000).connectionTimeoutMs(3000).retryPolicy(new ExponentialBackoffRetry(1000, 0)).build();
client.start();
nodeCache = new NodeCache(client, "/");
/**
* 监听子节点的变化情况
*/
watchChild();

}


protected static void watchChild() throws Exception {

nodeCache.getListenable().addListener(new NodeCacheListener() {


@Override
public void nodeChanged() throws Exception {
System.out.println(nodeCache.getCurrentData().getPath() + ":" + nodeCache.getCurrentData().getData());
}
}, EXECUTOR_SERVICE);
nodeCache.start();
}


public String getUrl() {
return url;
}


public void setUrl(String url) {
this.url = url;
}


public String getBasePath() {
return basePath;
}


public void setBasePath(String basePath) {
this.basePath = basePath;
}


public static void main(String[] args) throws Throwable {
CountDownLatch latch = new CountDownLatch(1);
client = CuratorFrameworkFactory.builder().namespace("o2o/zk/cache").connectString("192.168.200.98:2181").sessionTimeoutMs(5000).connectionTimeoutMs(3000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
client.start();


/**
* 监听子节点的变化情况
*/
watchChild("/");
latch.await();
}


}










Tree Node


这种类型的即可以监控节点的状态,还监控节点的子节点的状态, 类似上面两种cache的组合。 这也就是Tree的概念。 它监控整个树中节点的状态。(只要是所监听的路径下的所有叶子节点都会监听)


涉及到下面四个类。


TreeCache


TreeCacheListener


TreeCacheEvent


ChildData


构造TreeCache


而关键的TreeCache的构造函数为


public TreeCache(CuratorFramework client, String path)


添加监控节点状态


添加监控节点状态的改变的Listener时,建议使用此方法,手动传入我们构建的线程池,保证线程可控。


TreeCache.getListenable().(T listener, Executor executor);
想使用cache,依然要调用它的start方法,不用之后调用close方法。


getCurrentChildren()返回cache的状态,类型为Map。 而getCurrentData()返回监控的path的数据。


最后同样附一段完整代码


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.retry.ExponentialBackoffRetry;


/**
 * ZK链接
 * 
 * @author jiangzhixiong
 * @email xingxuan_jzx@foxmail.com
 * @date 2015年10月12日 下午5:18:21
 */
public class TreeClient {
// ip和端口url
private String url;
// 需要监听的base path
private String basePath;


private static CuratorFramework client = null;
private static TreeCache cache = null;
private static ZkTreeListener listener = new ZkTreeListener();
private static ExecutorService executorService = Executors.newSingleThreadExecutor();


public void init() throws Throwable {
if (basePath == null) {
basePath = "o2o/zk/cache";
}
// 修改重连次数,使用最初的线程进行重连监听,不重新新建线程 ExponentialBackoffRetry(1000, 0)
client = CuratorFrameworkFactory.builder().namespace(basePath).connectString(url).sessionTimeoutMs(5000).connectionTimeoutMs(3000).retryPolicy(new ExponentialBackoffRetry(1000, 10)).build();
client.start();
/**
* 监听子节点的变化情况
*/
watchChild("/product");
watchChild("/switch");


}


protected static void watchChild(String path) throws Exception {
// 改用TreeCacheListener,免除循环监听子节点的问题
cache = new TreeCache(client, path);
cache.getListenable().addListener(listener, executorService);
cache.start();
}


public String getUrl() {
return url;
}


public void setUrl(String url) {
this.url = url;
}


public String getBasePath() {
return basePath;
}


public void setBasePath(String basePath) {
this.basePath = basePath;
}


public static void main(String[] args) throws Throwable {
CountDownLatch latch = new CountDownLatch(1);
client = CuratorFrameworkFactory.builder().namespace("o2o/zk/cache").connectString("192.168.200.98:2181").sessionTimeoutMs(5000).connectionTimeoutMs(3000)
.retryPolicy(new ExponentialBackoffRetry(1000, 0)).build();
client.start();


/**
* 监听子节点的变化情况
*/
watchChild("/product");
                watchChild("/switch");
latch.await();
}


}
import java.util.Map;


import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;


import com.jd.o2o.web.product.constants.zk.ZkSwitchEnum;
import com.jd.o2o.web.product.constants.zk.ZkValueEnum;
import com.jd.o2o.zk.cache.serializer.ZooKeeperSerializer;
import com.jd.o2o.zk.cache.serializer.impl.JdkSerializationZooKeeperSerializer;


/**
 * TreeCache ZK监听器
 * 
 * @author jiangzhixiong
 * @email xingxuan_jzx@foxmail.com
 * @date 2015年10月12日 下午5:18:38
 */
public class ZkTreeListener implements TreeCacheListener {
private final Logger logger = LogManager.getLogger(TreeCacheListener .class);
private final ZooKeeperSerializer<?> defaultSerializer = new JdkSerializationZooKeeperSerializer();


@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
System.out.println(event.getData().getPath());
switch (event.getType()) {
case NODE_ADDED:
if (event.getData().getData() == null) {
break;
}
//TODO
break;
case NODE_UPDATED:
if (event.getData().getData() == null) {
break;
}
//TODO
break;
default:
break;
}
}

}



https://my.oschina.net/jiangzhixiong/blog/537706




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值