前言
在真正的项目中通常使用的是zkclient和curator,而不是原生的zookeeper客户端,因为zookeeper原生的客户端存在一定的局限性,本篇小编主要讲解一下这两种zookeeper客户端的使用!
内容
1.1zk原生api不足之处:
- 超时重连,不支持自动,需要手动操作
- Watch注册一次后失效
- 不支持递归创建节点
1.2zkclient
ZkClient是一个开源客户端,在Zookeeper原生API接口的基础上进行了包装,更便于开发人员使用。内部实现了Session超时重连,Watcher反复注册等功能。像dubbo等框架对其也进行了集成使用。
虽然ZkClient对原生API进行了封装,但也有它自身的不足之处:
- 几乎没有参考文档;
- 异常处理简化(抛出RuntimeException);
- 重试机制比较难用;
- 没有提供各种使用场景的实现;
zkclient简单代码示例:
package com.zk.dev.zkClient.day1;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
public class ZKTest {
private ZkClient zk;
private String nodeName = "/test";
@Before
public void initTest() {
zk = new ZkClient("localhost:2181");
}
@After
public void dispose() {
zk.close();
}
@Test
public void testListener() throws InterruptedException {
// 监听指定节点的数据变化
zk.subscribeDataChanges(nodeName, new IZkDataListener() {
public void handleDataChange(String s, Object o) throws Exception {
System.out.println("node data changed!");
System.out.println("node=>" + s);
System.out.println("data=>" + o);
System.out.println("--------------");
}
public void handleDataDeleted(String s) throws Exception {
System.out.println("node data deleted!");
System.out.println("s=>" + s);
System.out.println("--------------");
}
});
System.out.println("ready!");
// junit测试时,防止线程退出
while (true) {
TimeUnit.SECONDS.sleep(5);
}
}
@Test
public void testUpdateConfig() throws InterruptedException {
if (!zk.exists(nodeName)) {
//创建永久
zk.createPersistent(nodeName);
}
zk.writeData(nodeName, "1");
zk.writeData(nodeName, "2");
zk.delete(nodeName);
zk.delete(nodeName);
zk.writeData("/test/ba", "bbb");
}
}
1.3Apache curator
- Apache开源
- 解决watcher的注册一次就失效
- Api更加简单易用
- 提供跟多解决方案并且实现:比如分布式锁
- 提供常用的zookeeper工具类
- 编程风格更爽
curator简单代码示例:
package com.zk.dev.zkClient.day1;
import org.apache.curator.RetryPolicy;
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.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
public class CuratorUtils {
public String connectString = "localhost:2181";
CuratorFramework zkclient = null ;
public CuratorUtils(){
/**
* connectString连接字符串中间用分号隔开,sessionTimeoutMs session过期时间,connectionTimeoutMs连接超时时间,retryPolicyc连接重试策略
*/
//CuratorFrameworkFactory.newClient(connectString, sessionTimeoutMs, connectionTimeoutMs, retryPolicy)
// fluent风格aip
// CuratorFrameworkFactory.builder().sessionTimeoutMs(5000).connectString(connectString).namespace("/test").build();
// 重连策略,没1一秒重试一次,最大重试次数3次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
zkclient = CuratorFrameworkFactory.builder().connectString(connectString).sessionTimeoutMs(5000).retryPolicy(retryPolicy).namespace("tests").build();
zkclient.start();
}
/**
* 递归创建节点
* @param path
* @param data
* @throws Exception
*/
public void createNode(String path, byte[] data) throws Exception{
zkclient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(Ids.OPEN_ACL_UNSAFE).forPath(path, data);
}
/**
* 递归删除节点
* @param path
* @throws Exception
*/
public void delNode(String path) throws Exception{
zkclient.delete().guaranteed().deletingChildrenIfNeeded().forPath(path);
} public void zkClose(){
zkclient.close();
}
public void delNodeCallBack(String path) throws Exception{
zkclient.delete().guaranteed().deletingChildrenIfNeeded().inBackground(new DeleteCallBack()).forPath(path);
}
public void dataChanges(String path) throws Exception{
final NodeCache dataWatch = new NodeCache(zkclient, path);
dataWatch.start(true);
dataWatch.getListenable().addListener(new NodeCacheListener(){
public void nodeChanged() throws Exception {
System.out.println("path==>" + dataWatch.getCurrentData().getPath() + "==data==>" + new String(dataWatch.getCurrentData().getData()));
}
});
zkclient.delete().guaranteed().deletingChildrenIfNeeded().inBackground(new DeleteCallBack()).forPath(path);
}
public void addChildWatcher(String path) throws Exception{
final PathChildrenCache pc = new PathChildrenCache(zkclient, path, true);
pc.start(StartMode.POST_INITIALIZED_EVENT);
System.out.println("节点个数===>" + pc.getCurrentData().size());
pc.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
System.out.println("事件监听到" + event.getData().getPath());
if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
System.out.println("客户端初始化节点完成" + event.getData().getPath());
}else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
System.out.println("添加节点完成" + event.getData().getPath());
}else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
System.out.println("删除节点完成" + event.getData().getPath());
}else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
System.out.println("修改节点完成" + event.getData().getPath());
}
}
});
}
/*运行线程*/
public static void main(String[] args) throws Exception{
CuratorUtils cu = new CuratorUtils();
cu.zkclient.setData().forPath("/aa", "love is not".getBytes());
cu.addChildWatcher("/aa");
try{
Thread.sleep(20000000);
}catch(Exception e){};
}
}
curator结合spring:
pom中引入:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<!-- curator(zookeeper的客户端)包 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>${curator.version}</version>
</dependency>
<!--zookeeper重试策略-->
<bean id="retryPolicy" class="org.apache.curator.retry.RetryNTimes">
<!--重试次数-->
<constructor-arg index="0" value="10"></constructor-arg>
<!--每次的间隔-->
<constructor-arg index="1" value="5000"></constructor-arg>
</bean>
<!--zookeeper客户端-->
<bean id="client" class="org.apache.curator.framework.CuratorFrameworkFactory" factory-method="newClient" init-method="start">
<constructor-arg index="0" value="192.168.25.131:2181"/>
<!--session timeout 会话超时时间-->
<constructor-arg index="1" value="10000"/>
<!--创建连接的超时时间-->
<constructor-arg index="2" value="5000"/>
<!--重试策略-->
<constructor-arg index="3" ref="retryPolicy"/>
</bean>