ZooKeeper常用命令+ Curator使用详解

guide-rpc-framework 使用了 Zookeeper 来存储服务的相关信息 ,并且使用的是 ZooKeeper Java客户端 Curator 来对 ZooKeeper 进行增删改查等操作。

所以,本文就简单介绍一下 ZooKeeper常用命令 以及 Curator 的基本使用。

前言

这篇文章简单给演示一下 ZooKeeper 常见命令的使用以及 ZooKeeper Java客户端 Curator 的基本使用。介绍到的内容都是最基本的操作,能满足日常工作的基本需要。

ZooKeeper 安装和使用

使用Docker 安装 zookeeper

下载

  1. docker pull zookeeper:3.5.8

运行

  1. docker run -d --name zookeeper -p 2181:2181 zookeeper:3.5.8

连接 ZooKeeper 服务

a.进入ZooKeeper容器中
先使用 docker ps 查看 ZooKeeper 的 ContainerID,然后使用 docker exec -it ContainerID /bin/bash 命令进入容器中。

b.先进入 bin 目录,然后通过 ./zkCli.sh -server 127.0.0.1:2181命令连接ZooKeeper 服务

  1. root@eaf70fc620cb:/apache-zookeeper-3.5.8-bin# cd bin

如果你看到控制台成功打印出如下信息的话,说明你已经成功连接 ZooKeeper 服务。
a.png

ZooKeeper Java客户端 Curator简单使用

Curator 是Netflix公司开源的一套 ZooKeeper Java客户端框架,相比于 Zookeeper 自带的客户端 zookeeper 来说,Curator 的封装更加完善,各种 API 都可以比较方便地使用。

Curator4.0+版本对ZooKeeper 3.5.x支持比较好。开始之前,请先将下面的依赖添加进你的项目。

  1. <dependency>
  2. <groupId>org.apache.curator</groupId>
  3. <artifactId>curator-framework</artifactId>
  4. <version>4.2.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.curator</groupId>
  8. <artifactId>curator-recipes</artifactId>
  9. <version>4.2.0</version>
  10. </dependency>

连接 ZooKeeper 客户端

通过 CuratorFrameworkFactory 创建 CuratorFramework 对象,然后再调用 CuratorFramework 对象的 start() 方法即可!

  1. private static final int BASE_SLEEP_TIME = 1000;
  2. private static final int MAX_RETRIES = 3;
  3. // Retry strategy. Retry 3 times, and will increase the sleep time between retries.
  4. RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_TIME, MAX_RETRIES);
  5. CuratorFramework zkClient = CuratorFrameworkFactory.builder()
  6. // the server to connect to (can be a server list)
  7. .connectString("127.0.0.1:2181")
  8. .retryPolicy(retryPolicy)
  9. .build();
  10. zkClient.start();

对于一些基本参数的说明:

●baseSleepTimeMs:重试之间等待的初始时间
●maxRetries :最大重试次数
●connectString :要连接的服务器列表
●retryPolicy :重试策略

数据节点的增删改查

创建节点

我们在 ZooKeeper常见概念解读 中介绍到,我们通常是将 znode 分为 4 大类:

持久(PERSISTENT)节点 :一旦创建就一直存在即使 ZooKeeper 集群宕机,直到将其删除。
临时(EPHEMERAL)节点 :临时节点的生命周期是与 客户端会话(session) 绑定的,会话消失则节点消失 。并且,临时节点 只能做叶子节点 ,不能创建子节点。
持久顺序(PERSISTENT_SEQUENTIAL)节点 :除了具有持久(PERSISTENT)节点的特性之外, 子节点的名称还具有顺序性。比如 /node1/app0000000001 、/node1/app0000000002 。
临时顺序(EPHEMERAL_SEQUENTIAL)节点 :除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性。

你在使用的 ZooKeeper 的时候,会发现 CreateMode 类中实际有 7种 znode 类型 ,但是用的最多的还是上面介绍的 4 种。

a.创建持久化节点

你可以通过下面两种方式创建持久化的节点

  1. //注意:下面的代码会报错,下文说了具体原因
  2. zkClient.create().forPath("/node1/00001");
  3. zkClient.create().withMode(CreateMode.PERSISTENT).forPath("/node1/00002");

但是,你运行上面的代码会报错,这是因为的父节点node1还未创建。

你可以先创建父节点 node1 ,然后再执行上面的代码就不会报错了。

  1. zkClient.create().forPath("/node1");

更推荐的方式是通过下面这行代码, creatingParentsIfNeeded() 可以保证父节点不存在的时候自动创建父节点,这是非常有用的。

  1. zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node1/00001");

b.创建临时节点

  1. zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001");

c.创建节点并指定数据内容

  1. zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001","java".getBytes());
  2. zkClient.getData().forPath("/node1/00001");//获取节点的数据内容,获取到的是 byte数组

d.检测节点是否创建成功

  1. zkClient.checkExists().forPath("/node1/00001");//不为null的话,说明节点创建成功

删除节点
  1. zkClient.delete().forPath("/node1/00001"); //删除一个子节点
  2. zkClient.delete().deletingChildrenIfNeeded().forPath("/node1"); //删除一个节点以及其下的所有子节点

获取/更新节点数据内容
  1. zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001","java".getBytes());
  2. zkClient.getData().forPath("/node1/00001");//获取节点的数据内容
  3. zkClient.setData().forPath("/node1/00001","c++".getBytes());//更新节点数据内容

获取某个节点的所有子节点路径
  1. List<String> childrenPaths = zkClient.getChildren().forPath("/node1");

监听器

下面简单演示一下如何给某个节点注册子节点监听器 。注册了监听器之后,这个节点的子节点发生变化比如增加、减少或者更新的时候,你可以自定义回调操作。

  1. String path = "/node1";
  2. PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient, path, true);
  3. PathChildrenCacheListener pathChildrenCacheListener = (curatorFramework, pathChildrenCacheEvent) -> {
  4. // do something
  5. };
  6. pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
  7. pathChildrenCache.start();

如果你要获取节点事件类型的话,可以通过:

  1. pathChildrenCacheEvent.getType()

一共有下面几种类型:

  1. public static enum Type {
  2. CHILD_ADDED,//子节点增加
  3. CHILD_UPDATED,//子节点更新
  4. CHILD_REMOVED,//子节点被删除
  5. CONNECTION_SUSPENDED,
  6. CONNECTION_RECONNECTED,
  7. CONNECTION_LOST,
  8. INITIALIZED;
  9. private Type() {
  10. }
  11. }