Curator 使用示例

一、Curator 简介

Apache Curator 是一个比较完善的 ZooKeeper 客户端框架,通过封装的一套高级 API 简化了 ZooKeeper 的操作。通过查看官方文档,可以发现 Curator 主要解决了三类问题:

  1. 封装 ZooKeeper client 与 ZooKeeper server 之间的连接处理
  2. 提供了一套 Fluent 风格的操作 API
  3. 提供 ZooKeeper 各种应用场景 recipes, 比如:分布式锁服务、集群领导选举、共享计数器、缓存机制、分布式队列等)的抽象封装

Curator 主要从以下几个方面降低了 zk 使用的复杂性:

  • 重试机制: 提供可插拔的重试机制, 它将给捕获所有可恢复的异常配置一个重试策略,并且内部也提供了几种标准的重试策略(比如指数补偿)
  • 连接状态监控: Curator 初始化之后会一直对 zk 连接进行监听,一旦发现连接状态发生变化将会作出相应的处理
  • zk客户端实例管理: Curator 会对 zk 客户端到 server 集群的连接进行管理,并在需要的时候重建 zk 实例,保证与 zk 集群连接的可靠性
  • 各种使用场景支持: Curator 实现了 zk 支持的大部分使用场景(甚至包括 zk 自身不支持的场景),这些实现都遵循了 zk 的最佳实践,并考虑了各种极端情况

 

二、工程中引入 curator 依赖

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

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

 

三、示例(增删查改)


package com.topsail.curator;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class Demo1 {

public static void main(String[] args) throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
.connectString("192.168.181.128:2181,192.168.181.128:2182,192.168.181.128:2183")
.sessionTimeoutMs(4000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.namespace("namespace-demo1")
.build();

curatorFramework.start();

System.out.println(ZooKeeper.States.CONNECTED);
System.out.println(curatorFramework.getState());

createPersistent(curatorFramework, "/demo1/persistent");
createPersistentSeq(curatorFramework, "/demo1/persistent_seq");

createEphemeral(curatorFramework, "/demo1/ephemeral");
createEphemeralSeq(curatorFramework, "/demo1/ephemeral_seq");
dataOps(curatorFramework, "/demo1/persistent");
createPersistent(curatorFramework, "/demo1/a/b/c");
deleteCascade(curatorFramework, "/demo1/a");

}

/**
* 创建持久化节点
*
* @param curatorFramework
* @throws Exception
*/
private static void createPersistent(CuratorFramework curatorFramework, String path) throws Exception {
Stat stat = curatorFramework.checkExists().forPath(path);
if (Objects.isNull(stat)) {
curatorFramework.create()
.creatingParentContainersIfNeeded() // 如果指定节点的父节点不存在,则会自动级联创建父节点
.withMode(CreateMode.PERSISTENT)
.forPath(path, "=== CONTENT ===".getBytes());
System.out.println(path + " create success!");
} else {
System.out.println(path + " is exists!");
}
}

/**
* 获取某个节点数据,设置某个节点数据
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void dataOps(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.setData().forPath(path, "=== CONTENT ===".getBytes());
byte[] bytes = curatorFramework.getData().forPath(path);
System.out.println("->->-> " + new String(bytes));
}

/**
* 创建持久化顺序节点
*
* @param curatorFramework
* @throws Exception
*/
private static void createPersistentSeq(CuratorFramework curatorFramework, String path) throws Exception {
for (int i = 0; i < 5; i++) {
curatorFramework.create()
.creatingParentContainersIfNeeded() // 如果指定节点的父节点不存在,则会自动级联创建父节点
.withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath(path + "/i-", "persistent seq data".getBytes());

}

List<String> children = curatorFramework.getChildren().forPath(path);
Collections.sort(children);
for (String child : children) {
System.out.println("-> " + child);
}
}

/**
* 创建临时节点
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void createEphemeral(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.create()
.creatingParentContainersIfNeeded() // 如果指定节点的父节点不存在,则会自动级联创建父节点
.withMode(CreateMode.EPHEMERAL)
.forPath(path, "ephemeral data".getBytes());
}

/**
* 创建临时顺序节点
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void createEphemeralSeq(CuratorFramework curatorFramework, String path) throws Exception {
for (int i = 0; i < 5; i++) {
curatorFramework.create()
.creatingParentContainersIfNeeded() // 如果指定节点的父节点不存在,则会自动级联创建父节点
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(path + "/i-", "ephemeral seq data".getBytes());
}

List<String> children = curatorFramework.getChildren().forPath(path);
Collections.sort(children);
for (String child : children) {
System.out.println("EphemeralSeq -> " + child);
}
}

/**
* 删除节点
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void delete(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.delete().forPath(path);
}

/**
* 级联删除子节点
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void deleteCascade(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath(path);
}
}

 

四、示例(监听)


package com.topsail.curator;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class Demo2 {

public static void main(String[] args) throws Exception {
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.181.128:2181,192.168.181.128:2182,192.168.181.128:2183")
.sessionTimeoutMs(4000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.namespace("namespace-demo2")
.build();

client.start();
System.out.println(client.getState());

// PathChildCache 监听一个节点下子节点的创建、删除、修改事件
addListenerWithChildNodeCache(client, "/demo2/children");

// NodeCache 监听一个节点的修改和创建事件
addListenerWithNodeCache(client, "/demo2/single");

// TreeCache 监听所有节点的创建、删除、修改事件
addListenerWithTreeCache(client, "/demo2/tree");

System.in.read();

}

/**
* 监听某个节点的修改和创建事件
*
* @param curatorFramework
* @param path
*/
private static void addListenerWithNodeCache(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.create().creatingParentContainersIfNeeded().forPath(path);
NodeCache nodeCache = new NodeCache(curatorFramework, path, false);
NodeCacheListener nodeCacheListener = () -> {
ChildData currentData = nodeCache.getCurrentData();
System.out.println("监听到节点事件: " + currentData.getPath() + " -> " + new String(currentData.getData()));
};
nodeCache.getListenable().addListener(nodeCacheListener);
nodeCache.start();
}

/**
* 监听某个节点下子节点的创建、删除、修改事件
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void addListenerWithChildNodeCache(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.create().creatingParentContainersIfNeeded().forPath(path);
PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, true);
PathChildrenCacheListener pathChildrenCacheListener = (curatorFramework1, event) -> {
PathChildrenCacheEvent.Type type = event.getType();
switch (type) {
case CHILD_ADDED:
System.out.println("A child was added to the path:" + event.getType());
break;
case CHILD_UPDATED:
System.out.println("A child's data was changed:" + event.getType());
break;
case CHILD_REMOVED:
System.out.println("A child was removed from the path:" + event.getType());
break;
case CONNECTION_SUSPENDED:
System.out.println("CONNECTION_SUSPENDED:" + event.getType());
break;
case CONNECTION_RECONNECTED:
System.out.println("CONNECTION_RECONNECTED:" + event.getType());
break;
case CONNECTION_LOST:
System.out.println("CONNECTION_LOST:" + event.getType());
break;
case INITIALIZED:
System.out.println("INITIALIZED:" + event.getType());
break;
default:
break;
}
};

pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
pathChildrenCache.start();
}

/**
* 监听所有节点的创建、删除、修改事件
*
* @param curatorFramework
* @param path
* @throws Exception
*/
private static void addListenerWithTreeCache(CuratorFramework curatorFramework, String path) throws Exception {
curatorFramework.create().creatingParentContainersIfNeeded().forPath(path);
TreeCache treeCache = new TreeCache(curatorFramework, path);
TreeCacheListener treeCacheListener = (curatorFramework1, event) -> {
System.out.println("监听到节点事件:" + event.getType() + " - " + event.getData().getPath());
};

treeCache.getListenable().addListener(treeCacheListener);
treeCache.start();
}

}
 

 

五、示例(分布式锁)

package com.topsail.curator;

import org.apache.commons.lang3.RandomUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class Demo3 {

    public static void main(String[] args) throws Exception {
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                .connectString("192.168.181.128:2181,192.168.181.128:2182,192.168.181.128:2183")
                .sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .namespace("namespace-demo3")
                .build();

        curatorFramework.start();
        System.out.println(curatorFramework.getState());

        InterProcessMutex interProcessMutex = new InterProcessMutex(curatorFramework, "/locks");
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println("线程 " + Thread.currentThread().getId() + " 尝试抢占锁...");
                try {
                    interProcessMutex.acquire();
                    System.out.println("线程 " + Thread.currentThread().getId() + " 获取锁成功!");
                    Thread.sleep(RandomUtils.nextInt(1000, 2000));

                    interProcessMutex.release();
                    System.out.println("线程 " + Thread.currentThread().getId() + " 释放锁成功!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

 

六、示例(Leader选举)

package com.topsail.curator;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class Demo4 {

    public static void main(String[] args) throws Exception {
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("192.168.181.128:2181,192.168.181.128:2182,192.168.181.128:2183")
                .sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .namespace("namespace-demo4")
                .build();

        client.start();
        System.out.println(client.getState());

        String lockPath = "/leader";
        LeaderLatch leaderLatch = new LeaderLatch(client, lockPath);
        LeaderLatchListener listener = new LeaderLatchListener() {
            @Override
            public void isLeader() {
                System.out.println("i am master");
            }

            @Override
            public void notLeader() {
                System.out.println("i am salver");
            }
        };
        leaderLatch.addListener(listener);
        leaderLatch.start();
        leaderLatch.await();
    }
}

 

package com.topsail.curator;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.UUID;

@Component
public class Demo5 {

    private CuratorFramework client;
    private LeaderLatch leaderLatch;
    private String id = UUID.randomUUID().toString();

    @PostConstruct
    public void init() throws Exception {
        client = CuratorFrameworkFactory.builder()
                .connectString("192.168.181.128:2181,192.168.181.128:2182,192.168.181.128:2183")
                .sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .namespace("ns-demo5")
                .build();

        client.start();
        System.out.println("client 启动成功! " + client.getState());
        leaderLatch = new LeaderLatch(client, "/leader", id);
        leaderLatch.start();
    }

    @Scheduled(initialDelay = 2000, fixedDelay = 2000)
    public void execute() {
        System.err.println("id: " + id);
        if (leaderLatch.hasLeadership()) {
            System.err.println("Leadership...");
        }
    }
}

 

posted @ 2023-01-03 16:37  Steven.Chow  阅读(285)  评论(0编辑  收藏  举报