使用zookeeper原生API实现一些复杂的东西比较麻烦。所以,出现了两款比较好的开源客户端,对zookeeper的原生API进行了包装:zkClient和curator。后者是Netflix出版的,必属精品,也是最好用的zk的开源客户端。

一  curator基本API使用

引入依赖:

         <dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>

该依赖引入后,默认引入的zookeeper版本是3.4.8。

注意:不要引入>=3.0.0的curator-framework,默认引入的zookeeper版本是3.5.x(该版本还不稳定),目前测试起来还是有点问题的。

完整代码:

 package com.hulk.curator;

 import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat; import java.util.concurrent.Executors; public class CuratorTest {
private static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("10.211.55.4:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build(); public static void main(String[] args) throws Exception {
/**
* 创建会话
*/
client.start(); /**
* 创建节点
* 注意:
* 1 除非指明创建节点的类型,默认是持久节点
* 2 ZooKeeper规定:所有非叶子节点都是持久节点,所以递归创建出来的节点,只有最后的数据节点才是指定类型的节点,其父节点是持久节点
*/
client.create().forPath("/China");//创建一个初始内容为空的节点
client.create().forPath("/America", "zhangsan".getBytes());
client.create().withMode(CreateMode.EPHEMERAL).forPath("/France");//创建一个初始内容为空的临时节点
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/Russia/car", "haha".getBytes());//递归创建,/Russia是持久节点 /**
* 异步创建节点
* 注意:如果自己指定了线程池,那么相应的操作就会在线程池中执行,如果没有指定,那么就会使用Zookeeper的EventThread线程对事件进行串行处理
*/
client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getName() + ",code:" + event.getResultCode()
+ ",type:" + event.getType());
}
}, Executors.newFixedThreadPool(10)).forPath("/async-curator-my"); client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getName() + ",code:" + event.getResultCode()
+ ",type:" + event.getType());
}
}).forPath("/async-curator-zookeeper"); /**
* 获取节点内容
*/
byte[] data = client.getData().forPath("/America");
System.out.println(new String(data));
byte[] data2 = client.getData().storingStatIn(new Stat()).forPath("/America"); //传入一个旧的stat变量,来存储服务端返回的最新的节点状态信息
System.out.println(new String(data2));
/**
* 更新数据
*/
Stat stat = client.setData().forPath("/America");
client.setData().withVersion(4).forPath("/America", "lisi".getBytes()); /**
* 删除节点
*/
client.delete().forPath("/China");//只能删除叶子节点
client.delete().deletingChildrenIfNeeded().forPath("/Russia");//删除一个节点,并递归删除其所有子节点
client.delete().withVersion(5).forPath("/America");//强制指定版本进行删除
client.delete().guaranteed().forPath("/America");//注意:由于一些网络原因,上述的删除操作有可能失败,使用guaranteed(),如果删除失败,会记录下来,只要会话有效,就会不断的重试,直到删除成功为止 Thread.sleep(Integer.MAX_VALUE);
}
}

1  创建会话

curator创建会话有两种方式,推荐流式API。

 CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("10.211.55.4:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();

参数:

  • connectString:zk的server地址,多个server之间使用英文逗号分隔开
  • connectionTimeoutMs:连接超时时间,如上是30s,默认是15s
  • sessionTimeoutMs:会话超时时间,如上是50s,默认是60s
  • retryPolicy:失败重试策略
    • ExponentialBackoffRetry:构造器含有三个参数 ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs)

      • baseSleepTimeMs:初始的sleep时间,用于计算之后的每次重试的sleep时间,

        • 计算公式:当前sleep时间=baseSleepTimeMs*Math.max(1, random.nextInt(1<<(retryCount+1)))
      • maxRetries:最大重试次数
      • maxSleepMs:最大sleep时间,如果上述的当前sleep计算出来比这个大,那么sleep用这个时间
    • 其他,查看org.apache.curator.RetryPolicy接口的实现类

此时会话还没创建,使用如下代码创建会话:

 client.start();

start()会阻塞到会话创建成功为止。

2  创建节点

2.1  同步创建

         client.create().forPath("/China");//创建一个初始内容为空的节点
client.create().forPath("/America", "zhangsan".getBytes());
client.create().withMode(CreateMode.EPHEMERAL).forPath("/France");//创建一个初始内容为空的临时节点
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/Russia/car", "haha".getBytes());//递归创建,/Russia是持久节点

注意:

  • 除非指明创建节点的类型,默认是持久节点
  • ZooKeeper规定:所有非叶子节点都是持久节点,所以递归创建出来的节点,只有最后的数据节点才是指定类型的节点,其父节点是持久节点
  • creatingParentsIfNeeded():可以实现递归创建

2.2  异步创建

         client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getName() + ",code:" + event.getResultCode()
+ ",type:" + event.getType());
}
}, Executors.newFixedThreadPool(10)).forPath("/async-curator-my"); client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getName() + ",code:" + event.getResultCode()
+ ",type:" + event.getType());
}
}).forPath("/async-curator-zookeeper");

注意:

  • 在curator中所有异步操作,都使用org.apache.curator.framework.api.BackgroundCallback接口的实现类完成
  • 如果在BackgroundCallback中自己指定了线程池,那么相应的操作就会在线程池中执行,如果没有指定,那么就会使用Zookeeper的EventThread线程对事件进行串行处理,所以上述的两个输出分别如下:
    当前线程:pool-3-thread-1,code:0,type:CREATE
    当前线程:main-EventThread,code:0,type:CREATE

3  获取节点内容

         byte[] data = client.getData().forPath("/America");
System.out.println(new String(data));
byte[] data2 = client.getData().storingStatIn(new Stat()).forPath("/America"); //传入一个旧的stat变量,来存储服务端返回的最新的节点状态信息
System.out.println(new String(data2));

4  获取节点子节点列表

 List<String> children = client.getChildren().forPath("/Russia");

5  更新数据

         Stat stat = client.setData().forPath("/America");
client.setData().withVersion(4).forPath("/America", "lisi".getBytes());

注意:

  • version版本号还是为了实现CAS并发处理,也会强制某个线程必须更新相应的版本的数据

6  删除节点

         client.delete().forPath("/China");//只能删除叶子节点
client.delete().deletingChildrenIfNeeded().forPath("/Russia");//删除一个节点,并递归删除其所有子节点
client.delete().withVersion(5).forPath("/America");//强制指定版本进行删除
client.delete().guaranteed().forPath("/America");

注意:

  • deletingChildrenIfNeeded()实现级联删除
  • guaranteed()由于一些网络原因,上述的删除操作有可能失败,使用guaranteed(),如果删除失败,会记录下来,只要会话有效,就会不断的重试,直到删除成功为止

二  curator实现事件监听

引入两个依赖:

         <dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>

给出全部代码:

 package com.hulk.curator;

 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.retry.ExponentialBackoffRetry; /**
* 事件监听器
*/
public class CuratorWatcherTest {
private static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("10.211.55.4:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build(); public static void main(String[] args) throws Exception {
/**
* 创建会话
*/
client.start();
client.create().creatingParentsIfNeeded().forPath("/book/computer","java".getBytes());
/**
* 监听指定节点本身的变化,包括节点本身的创建和节点本身数据的变化
*/
NodeCache nodeCache = new NodeCache(client,"/book/computer");
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("新的节点数据:" + new String(nodeCache.getCurrentData().getData()));
}
});
nodeCache.start(true); client.setData().forPath("/book/computer","c++".getBytes());
/**
* 监听子节点变化情况
* 1 新增子节点
* 2 删除子节点
* 3 子节点数据变更
*/
PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/book13",true);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()){
case CHILD_ADDED:
System.out.println("新增子节点:" + event.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("子节点数据变化:" + event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("删除子节点:" + event.getData().getPath());
break;
default:
break;
}
}
});
pathChildrenCache.start(); client.create().forPath("/book13"); client.create().forPath("/book13/car", "bmw".getBytes()); client.setData().forPath("/book13/car", "audi".getBytes()); client.delete().forPath("/book13/car");
}
}

curator的事件监听分为:

  • NodeCache:对节点本身的监听

    • 监听节点本身的创建
    • 监听节点本身的数据的变化
  • PathChildrenCache:对节点的子节点的监听
    • 监听新增子节点
    • 监听删除子节点
    • 监听子节点数据变化

注意

  • PathChildrenCache只会监听指定节点的一级子节点,不会监听节点本身(例如:“/book13”),也不会监听子节点的子节点(例如,“/book13/car/color”)

三  zkui

zk的操作我们一般可以登上zk所在的机器,然后执行“sh zkCli.sh”,之后执行一些命令,但是由于这样始终效率低下,这里推荐一款比较好用的zk的ui界面:zkui。

假设我们要在10.211.55.5机器上安装该程序。

1  下载打包

 git clone https://github.com/DeemOpen/zkui.git
cd zkui/
mvn clean install

通过上述的操作,在zkui/target目录下我们会生成一个fatjar:zkui-2.0-SNAPSHOT-jar-with-dependencies.jar,在启动这个jar之前先要进行相关配置。

2  配置zkui

 cp config.cfg target/
vi config.cfg
修改内容如下,其他不变:
zkServer=10.211.55.5:2181

注意:需要将配置文件config.cfg与fatjar放在同一个目录下。

3  启动zkui

之后进入target/目录下,执行:

 nohup java -jar zkui-2.0-SNAPSHOT-jar-with-dependencies.jar &

4  浏览器访问

浏览器访问“http://10.211.55.5:9090”,之后在登录页面输入用户名密码:admin/manager进行登录。(可以去config.cfg进行配置)

7.5 zookeeper客户端curator的基本使用 + zkui的更多相关文章

  1. Zookeeper客户端Curator使用详解

    Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...

  2. 转:Zookeeper客户端Curator使用详解

    原文:https://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBo ...

  3. Zookeeper客户端Curator基本API

    在使用zookeper的时候一般不使用原生的API,Curator,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连.反复注册Watcher和NodeExistsExceptio ...

  4. Zookeeper客户端Curator的使用,简单高效

    Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量. 1.引入依赖: ...

  5. zookeeper(六):Zookeeper客户端Curator的API使用详解

    简介 Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连.反复注册Watcher和NodeExistsEx ...

  6. 聊聊、Zookeeper 客户端 Curator

    [Curator]   和 ZkClient 一样,Curator 也是开源客户端,Curator 是 Netflix 公司开源的一套框架. <dependency> <groupI ...

  7. Zookeeper客户端 CuratorFramework使用

    CuratorFramework使用 跟着实例学习ZooKeeper的用法: Curator框架应用 ZooKeeper客户端Curator使用一 创建连接

  8. 八:Zookeeper开源客户端Curator的api测试

    curator是Netflix公司开源的一套ZooKeeper客户端,Curator解决了很多ZooKeeper客户端非常底层的细节开发工作.包括连接重连,反复注册Watcher等.实现了Fluent ...

  9. zookeeper客户端使用第三方(Curator)封装的Api操作节点

    1.为什么使用Curator? Curator本身是Netflix公司开源的zookeeper客户端: Curator  提供了各种应用场景的实现封装: curator-framework  提供了f ...

随机推荐

  1. 使用eclipse svn塔建(配置)时的一点点心得

    有没有人遇到下面这种情况??自己创建的SVN如下: 但网上别人搭建好的是这样子的: 就是为什么我的只有个主文件,而没有src.webroot.meta-inf.web-inf等子文件呢?? 这是我找了 ...

  2. ubantu18.04下Hadoop安装与伪分布式配置

    1  下载 下载地址:http://mirror.bit.edu.cn/apache/hadoop/common/stable2/ 2 解压 将文件解压到 /usr/local/hadoop cd ~ ...

  3. Java NIO-3

    http://itindex.net/detail/55603-java-nio-%E6%8A%80%E6%9C%AF

  4. jQuery方法实现

    children 原生JavaScript中,如果希望找到某个元素的子元素,只能通过Node类型上的children方法一步一步获取.如 let li = document.querySelector ...

  5. BZOJ.1923.[SDOI2010]外星千足虫(高斯消元 异或方程组 bitset)

    题目链接 m个方程,n个未知量,求解异或方程组. 复杂度比较高,需要借助bitset压位. 感觉自己以前写的(异或)高斯消元是假的..而且黄学长的写法都不需要回代. //1100kb 324ms #i ...

  6. 【莫队算法】【权值分块】bzoj3920 Yuuna的礼物

    [算法一] 暴力. 可以通过第0.1号测试点. 预计得分:20分. [算法二] 经典问题:区间众数,数据范围也不是很大,因此我们可以: ①分块,离散化,预处理出: <1>前i块中x出现的次 ...

  7. Anaconda、Miniconda、Conda、pip的相互关系_我是刘振岗_新浪博客

    Anaconda.Miniconda.Conda.pip的相互关系_我是刘振岗_新浪博客 http://blog.sina.com.cn/s/blog_8a122dcf0102x9vn.html

  8. oracle 删除字段中空格

    update  sales_report set region =  REGEXP_REPLACE(region,  '( ){1,}', '')

  9. 【Go命令教程】7. go run

    Go 源码文件包括:命令源码文件.库源码文件 和 测试源码文件.其中,命令源码文件 总应该属于 main 代码包,且在其中有无参数声明.无结果声明的 main 函数.单个命令源码文件可以被单独编译,也 ...

  10. perl 信号

    来自:http://www.bagualu.net/wordpress/?p=1628 使用signal,能让你的程序功能更丰富.要在Linux下列出所有的signal, 利用kill -l即可. 下 ...