Zookeeper利器 Curator 基本使用(一)

·  阅读 765

Zookeeper利器 Curator 基本使用(一)

前言

原生的zk api开发却比较繁琐,效率低下,Curator框架是apache提供的一款zkClient。

一. 建立连接

使用curator框架,需要往pom文件里添加依赖

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>
复制代码

通过CuratorFramework建立与zk的连接,CutartorFactory创建zkClient方法暴露了两个方法 newClient和 builder,但实际上戳进源码就会发现 newClient方法在实现时,最终也是调用了build

curatorFactory的newClient重载了两个方法

public static CuratorFramework newClient(String connectString, RetryPolicy retryPolicy)
public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy)复制代码
  • connectString:zkServers的 host:port 字符串,集群环境下,每一实例通过逗号分隔
  • retryPolicy:重试策略
  • sessionTimeoutMs:会话超时时间 默认为60*1000 ms
  • connectionTimeoutMs:连接超时时间 默认为15*1000 ms

示例代码

final String ZK_SERVERS = "localhost:2181,localhost:2182,localhost:2183";
final int RETRY_TIMES = 3;
final int RETRY_INTERVAL_MILLIONS_SECONDS = 5000;
final int sessionTimeoutMs = 60 * 1000;
final int connectionTimeoutMs = 15 * 1000;
​
final RetryPolicy retry = new ExponentialBackoffRetry(RETRY_INTERVAL_MILLIONS_SECONDS, RETRY_TIMES);
CuratorFramework client = CuratorFrameworkFactory.newClient(ZK_SERVERS, retry);
CuratorFramework client2 = CuratorFrameworkFactory.builder()
        .connectString(ZK_SERVERS)
        .sessionTimeoutMs(sessionTimeoutMs)
        .connectionTimeoutMs(connectionTimeoutMs)
        .retryPolicy(retry)
        .build();
client.start();
复制代码

ExponentialBackoffRetry是比较常用的重试策略,实例代码中的实现为3次重试,每次重试间隔5000ms,会话时间和连接超时时间可以不设定 使用curator默认的时间。需特别注意 client.start() ,start方法只需要执行一次,如果在代码中重复调用,则会抛异常 throw new IllegalStateException("Cannot be started more than once");

二. 新建节点

client.create().forPath("/5AnJam");
client.create().withMode(CreateMode.EPHEMERAL).forPath("/5AnJam/test","Hello world".getBytes(StandardCharsets.UTF_8));
​
List<String> l = client.getChildren().forPath("/5AnJam");
System.out.println(Arrays.toString(l.toArray()));
​
String val1 = new String(client.getData().forPath("/5AnJam/test"));
System.out.println(val1);复制代码

curator通过create().forPath新建节点,forPath接受参数(String path,byte[ ] data),也可以不设置data默认为空,可以通过withMode来设置节点类型,curator默认为永久节点,有 "7" 种类型与zookeeper的ZNode类型一一对应,通常的八股文我们都会认为ZNode有4种类型,但实际上,ZNode共有7种类型,(此处用curator中的节点类型进行说明)

public enum CreateMode {
    PERSISTENT(0, false, false, false, false),
    PERSISTENT_SEQUENTIAL(2, false, true, false, false),
    EPHEMERAL(1, true, false, false, false),
    EPHEMERAL_SEQUENTIAL(3, true, true, false, false),
    CONTAINER(4, false, false, true, false),
    PERSISTENT_WITH_TTL(5, false, false, false, true),
    PERSISTENT_SEQUENTIAL_WITH_TTL(6, false, true, false, true);
    
        private CreateMode(int flag, boolean ephemeral, boolean sequential, boolean isContainer, boolean isTTL) {
        this.flag = flag;
        this.ephemeral = ephemeral;
        this.sequential = sequential;
        this.isContainer = isContainer;
        this.isTTL = isTTL;
    }
}
复制代码

重点关注后面的3种节点

  • CONTAINER 容器节点:容器节点与持久节点很类似,但不同的是,当Zk服务启动的时候会去扫描容器节点下是否存在子节点,在curator的表现为 getChildren() 方法,如果为空,则会删除该节点。
  • PERSISTENT_WITH_TTL:TTL即Time To Live,译为节点的存活时间,持久节点永远存活,而临时节点存活时间与客户端连接相关,如果想要建立一个带有过期时间的节点,则可以用它。
  • PERSISTENT_SEQUENTIAL_WITH_TTL:与PERSISTENT_WITH_TTL类似,只不过它是有序的。

Tips

  1. 节点存在时不可再次建立,否则会报异常
  2. ZK的节点不允许递归建立,在上述代码中显示创建了持久节点 /5AnJam 再建立的节点 /5AnJam/test,但不可以省略第一步,直接创建 /5AnJam/Test
  3. 临时节点不可创建子节点,子节点只能创建在持久节点下

三. 修改节点值

client.setData().forPath("/5AnJam/test","Hello again".getBytes(StandardCharsets.UTF_8));
String val2 = new String(client.getData().forPath("/5AnJam/test"));
System.out.println(val2);
复制代码

curator可以通过setData().forPath修改节点的值,但如果节点不存在,则会报错

四. 删除节点

 client.delete().forPath("/5AnJam/test");
 client.delete().forPath("/5AnJam");
 Stat nodeStat = client.checkExists().forPath("/5AnJam");
 System.out.println(null == nodeStat);
复制代码

curator可以通过delete().forPath删除节点,同样的新建节点类似,删除节点也不会递归删除,需要自下而上的删除,否则会抛异常,删除节点后 可以通过 checkExists().forPath方法来校验节点是否删除成功 若成功 返回的stat 则为null

五.节点监听

        NodeCache nodeCache = new NodeCache(client,"/5AnJam");
        nodeCache.start(true);
        nodeCache.getListenable().addListener(() -> {
            System.out.println(new String(nodeCache.getCurrentData().getData()));
        });
        client.create().forPath("/5AnJam");
        client.setData().forPath("/5AnJam","1".getBytes(StandardCharsets.UTF_8));
        client.setData().forPath("/5AnJam","2".getBytes(StandardCharsets.UTF_8));
        client.setData().forPath("/5AnJam","3".getBytes(StandardCharsets.UTF_8));
        client.setData().forPath("/5AnJam","4".getBytes(StandardCharsets.UTF_8));
        while(true);
复制代码

NodeCache提供了节点监听的功能,cache缓存的概念即当前节点与zk服务端的节点对比,若不一样则会触发监听机制。

六.完整示例代码

public static void main(String[] args) throws Exception {
    final String ZK_SERVERS = "localhost:2181,localhost:2182,localhost:2183";
    final int RETRY_TIMES = 3;
    final int RETRY_INTERVAL_MILLIONS_SECONDS = 5000;
    final int sessionTimeoutMs = 60 * 1000;
    final int connectionTimeoutMs = 15 * 1000;

    final RetryPolicy retry = new ExponentialBackoffRetry(RETRY_INTERVAL_MILLIONS_SECONDS, RETRY_TIMES);
    CuratorFramework client = CuratorFrameworkFactory.newClient(ZK_SERVERS, retry);
    CuratorFramework client2 = CuratorFrameworkFactory.builder()
            .connectString(ZK_SERVERS)
            .sessionTimeoutMs(sessionTimeoutMs)
            .connectionTimeoutMs(connectionTimeoutMs)
            .retryPolicy(retry)
            .build();

    client.start();
    client.create().forPath("/5AnJam");
    client.create().withMode(CreateMode.EPHEMERAL).forPath("/5AnJam/test","Hello world".getBytes(StandardCharsets.UTF_8));

    List<String> l = client.getChildren().forPath("/5AnJam");
    System.out.println(Arrays.toString(l.toArray()));

    String val1 = new String(client.getData().forPath("/5AnJam/test"));
    System.out.println(val1);

    client.setData().forPath("/5AnJam/test","Hello again".getBytes(StandardCharsets.UTF_8));
    String val2 = new String(client.getData().forPath("/5AnJam/test"));
    System.out.println(val2);

    client.delete().forPath("/5AnJam/test");
    client.delete().forPath("/5AnJam");
    Stat nodeStat = client.checkExists().forPath("/5AnJam");
    System.out.println(null == nodeStat);
    
    NodeCache nodeCache = new NodeCache(client,"/5AnJam");
    nodeCache.start(true);
    nodeCache.getListenable().addListener(() -> {
        System.out.println(new String(nodeCache.getCurrentData().getData()));
    });
    client.create().forPath("/5AnJam");
    client.setData().forPath("/5AnJam","1".getBytes(StandardCharsets.UTF_8));
    client.setData().forPath("/5AnJam","2".getBytes(StandardCharsets.UTF_8));
    client.setData().forPath("/5AnJam","3".getBytes(StandardCharsets.UTF_8));
    client.setData().forPath("/5AnJam","4".getBytes(StandardCharsets.UTF_8));
    client.delete().forPath("/5AnJam");
    while(true);
}
复制代码

\

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改