使用Apache Curator操作Zookeeper

什么是Curator?

Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等等。并且提供了一些工具类,还可以更简单的实现例如分布式锁。

POM依赖

		<!-- 对zookeeper的底层api的一些封装。-->
		<dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>
        <!-- 封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等。。-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>

重试策略

1.ExponentialBackoffRetry

	public ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries)
    {
        this(baseSleepTimeMs, maxRetries, DEFAULT_MAX_SLEEP_MS);
    }

/**
     * @param baseSleepTimeMs initial amount of time to wait between retries
     * @param maxRetries max number of times to retry
     * @param maxSleepMs max time in ms to sleep on each retry
     */
    public ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs)
    {
        super(validateMaxRetries(maxRetries));
        this.baseSleepTimeMs = baseSleepTimeMs;
        this.maxSleepMs = maxSleepMs;
    }

2.RetryNTimes

	/**
	* n 代表尝试n次
	* sleepMsBetweenRetries 每次尝试的间隔为sleepMsBetweenRetries毫秒
	**/
	public RetryNTimes(int n, int sleepMsBetweenRetries)
    {
        super(n);
        this.sleepMsBetweenRetries = sleepMsBetweenRetries;
    }

3.RetryOneTime

	//只重试一次
	public RetryOneTime(int sleepMsBetweenRetry)
    {
        super(1, sleepMsBetweenRetry);
    }

4.RetryForever

	// 永远重试  不推荐
	public RetryForever(int retryIntervalMs)
    {
        checkArgument(retryIntervalMs > 0);
        this.retryIntervalMs = retryIntervalMs;
    }

5.RetryUntilElapsed

	/**
	* maxElapsedTimeMs:最大重试时间
	* sleepMsBetweenRetries:每次重试间隔
	* 重试时间超过maxElapsedTimeMs后,就不再重试
	**/
	public RetryUntilElapsed(int maxElapsedTimeMs, int sleepMsBetweenRetries)
    {
        super(Integer.MAX_VALUE);
        this.maxElapsedTimeMs = maxElapsedTimeMs;
        this.sleepMsBetweenRetries = sleepMsBetweenRetries;
    }

Curator出现的问题

Caused by: org.apache.zookeeper.KeeperException$UnimplementedException: KeeperErrorCode = Unimplemented for /tasks/b5957aa6-e250-41e0-a39b-521da61ca937
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:103) ~[zookeeper-3.5.3-beta.jar:3.5.3-beta-8ce24f9e675cbefffb8f21a47e06b42864475a60]
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:51) ~[zookeeper-3.5.3-beta.jar:3.5.3-beta-8ce24f9e675cbefffb8f21a47e06b42864475a60]
    at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:1525) ~[zookeeper-3.5.3-beta.jar:3.5.3-beta-8ce24f9e675cbefffb8f21a47e06b42864475a60]
    at org.apache.curator.framework.imps.CreateBuilderImpl$17.call(CreateBuilderImpl.java:1181) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.framework.imps.CreateBuilderImpl$17.call(CreateBuilderImpl.java:1158) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.connection.StandardConnectionHandlingPolicy.callWithRetry(StandardConnectionHandlingPolicy.java:64) ~[curator-client-4.0.1.jar:na]
    at org.apache.curator.RetryLoop.callWithRetry(RetryLoop.java:100) ~[curator-client-4.0.1.jar:na]
    at org.apache.curator.framework.imps.CreateBuilderImpl.pathInForeground(CreateBuilderImpl.java:1155) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.framework.imps.CreateBuilderImpl.protectedPathInForeground(CreateBuilderImpl.java:605) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:595) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:573) ~[curator-framework-4.0.1.jar:4.0.1]
    at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:49) ~[curator-framework-4.0.1.jar:4.0.1]

遇到这种情况,可是能你引的依赖版本有问题。注意检查。我就碰到了,记录一下。
在这里插入图片描述
Curator4.0只能使用zk3.5.x。如果想用3.4.x的zk,那么必须排出掉Curator包里的zk。

创建客户端

// zkServerPath为zk机器ip及端口号
client = CuratorFrameworkFactory.builder()
                .connectString(zkServerPath)
                .sessionTimeoutMs(10000).retryPolicy(retryPolicy)
                .namespace("workspace").build();
client.start();

创建节点

client.create().creatingParentContainersIfNeeded()
                .withMode(CreateMode.PERSISTENT)
                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
                .forPath(nodePath, "fyy".getBytes());

creatingParentContainersIfNeeded如果父节点不存在,那么也会创建。
在这里插入图片描述

设置节点值

byte[] newData = "batman".getBytes();
client.setData().withVersion(0).forPath(nodePath, newData);

withVersion是dataVersion版本号.

删除节点

 // 删除节点
client.delete()
	  .guaranteed()//
	  .deletingChildrenIfNeeded()// 如果有子节点,就删除
	  .withVersion(0)
	  .forPath(nodePath);

在这里插入图片描述
只要客户端会话有效,那么Curator会在后台持续进行删除操作,直到节点删除成功。防止成功操作响应未被客户端接收的情况。

读取节点信息

Stat stat = new Stat();
byte[] data = client.getData().storingStatIn(stat).forPath(nodePath);
System.out.println("节点" + nodePath + "的数据为: " + new String(data));
System.out.println("该节点的版本号为: " + stat.getVersion());

查询子节点信息

List<String> childNodes = client.getChildren()
								.forPath(nodePath);
System.out.println("开始打印子节点:");
// 打印子节点名称
for (String s : childNodes) {
	System.out.println(s);
}

判断子节点是否存在

Stat statExist = client.checkExists().forPath(nodePath + "/abc");
// null 表示不存在
System.out.println(statExist);

Watcher事件监听

client.getData().usingWatcher(new MyCuratorWatcher()).forPath(nodePath);

在这里插入图片描述
有两种接口,不过它们都是注册一次只能监听一次。

1次注册watcherN次监听

final NodeCache nodeCache = new NodeCache(cto.client, nodePath);
// buildInitial : 初始化的时候获取node的值并且缓存
nodeCache.start(true);// false 初始化为null
if (nodeCache.getCurrentData() != null) {
	System.out.println("节点初始化数据为:" + new String(nodeCache.getCurrentData().getData()));
} else {
	System.out.println("节点初始化数据为空...");
}
// getListenable是获取监听器集合。并加入我们需要的监听器
nodeCache.getListenable().addListener(new NodeCacheListener() {
	public void nodeChanged() throws Exception {
		if (nodeCache.getCurrentData() == null) {
			System.out.println("空");
			return;
		}
		String data = new String(nodeCache.getCurrentData().getData());
		System.out.println("节点路径:" + nodeCache.getCurrentData().getPath() + "数据:" + data);
	}
});

在这里插入图片描述

// cacheData: 设置缓存节点的数据状态
final PathChildrenCache childrenCache = new PathChildrenCache(cto.client, childNodePathCache, true);
/**
 * StartMode: 初始化方式
 * POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件
 * NORMAL:异步初始化
 * BUILD_INITIAL_CACHE:同步初始化
 */
childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);

List<ChildData> childDataList = childrenCache.getCurrentData();
System.out.println("当前数据节点的子节点数据列表:");
for (ChildData cd : childDataList) {
    String childData = new String(cd.getData());
    System.out.println(childData);
}

childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
    public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
        if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
            System.out.println("子节点初始化ok...");
        }

        else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
            String path = event.getData().getPath();
            System.out.println("添加子节点:" + event.getData().getPath());
            System.out.println("子节点数据:" + new String(event.getData().getData()));
        }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());
            System.out.println("修改子节点数据:" + new String(event.getData().getData()));
        }
    }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值