Curator基础

Curator简介

Curator框架提供了一套高级的API, 简化了ZooKeeper的操作. 它增加了很多使用ZooKeeper开发的特性, 可以处理ZooKeeper集群复杂的连接管理和重试机制.

Maven依赖


  org.apache.zookeeper
  zookeeper
  3.4.6


  org.apache.curator
  curator-client
  4.0.0


  org.apache.curator
  curator-framework
  4.0.0


  org.apache.curator
  curator-recipes
  4.0.0

Curator操作

CuratorFramework提供的方法:

方法名 描述
create() 创建操作, 可以调用额外的方法(比如节点类型withMode或者后台处理inBackground), 并在最后调用forPath()指定要操作的ZNode
checkExists() 检查ZNode是否存在的操作. 可以调用额外的方法(监控或者后台处理), 并在最后调用forPath()指定要操作的ZNode
getData() 获得ZNode节点数据的操作. 可以调用额外的方法(监控、后台处理或者获取状态), 并在最后调用forPath()指定要操作的ZNode
setData() 设置ZNode节点数据的操作. 可以调用额外的方法(版本或者后台处理), 并在最后调用forPath()指定要操作的ZNode
getChildren() 获得ZNode的子节点列表. 可以调用额外的方法(监控、后台处理或者获取状态), 并在最后调用forPath()指定要操作的ZNode
delete() 删除操作. 可以调用额外的方法(版本或者后台处理), 并在最后调用forPath()指定要操作的ZNode
inTransaction() 原子ZooKeeper事务. 可以复合create, setData, check, and/or delete 等操作, 然后调用commit()作为一个原子操作提交
public class CuratorBase {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    public static void main(String[] args) throws Exception {
        //1 重连策略:每隔1s重连一次,重连10次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
        //2 通过工厂创建连接
        CuratorFramework cf = CuratorFrameworkFactory.builder()
                    .connectString(CONNECT_ADDR)
                    .sessionTimeoutMs(SESSION_OUTTIME)
                    .retryPolicy(retryPolicy)
                    .build();
        //3 开启连接
        cf.start();

        //4 创建一个持久节点
        cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).inBackground().forPath("/super/c1","c1内容".getBytes());

        //5 判断节点是否存在
        Stat stat = cf.checkExists().forPath("/super/c1");
        if(stat==null){
            System.out.println("Node does not exists");
        }else {
            System.out.println("Node exists and the node version is " +
                    stat.getVersion());
        }

        //6 读取节点数据
        String ret1 = new String(cf.getData().forPath("/super/c1"));
        System.out.println(ret1);

        //7 修改节点
        cf.setData().forPath("/super/c1", "修改c1内容".getBytes());
        String ret2 = new String(cf.getData().forPath("/super/c1"));
        System.out.println(ret2);

        //8 查看是否有子节点
        List list = cf.getChildren().forPath("/super");
        for(String p : list){
            System.out.println(p);
        }

        //9 级联删除节点
        cf.delete().guaranteed().deletingChildrenIfNeeded().forPath("/super");
    }
}

节点监听器(Znode Watcher)

监听根节点

public class CuratorWatcher1 {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    public static void main(String[] args) throws Exception {
        //1 重连策略:每隔1s重连一次,重连10次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
        //2 通过工厂创建连接
        CuratorFramework cf = CuratorFrameworkFactory.builder()
                .connectString(CONNECT_ADDR)
                .sessionTimeoutMs(SESSION_OUTTIME)
                .retryPolicy(retryPolicy)
                .build();
        //3 开启连接
        cf.start();

        //4 建立一个cache缓存
        final NodeCache cache = new NodeCache(cf, "/super", false);
        cache.start(true);
        // 5 添加监听器
        cache.getListenable().addListener(new NodeCacheListener() {
            /**
             * 方法名称:nodeChanged
             * 概要说明:触发事件为创建节点和更新节点,在删除节点的时候并不触发此操作。
             */
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("路径为:" + cache.getCurrentData().getPath());
                System.out.println("数据为:" + new String(cache.getCurrentData().getData()));
                System.out.println("状态为:" + cache.getCurrentData().getStat());
                System.out.println("---------------------------------------");
            }
        });

        Thread.sleep(1000);
        cf.create().forPath("/super", "123".getBytes()); //触发

        Thread.sleep(1000);
        cf.setData().forPath("/super", "456".getBytes()); //触发

        Thread.sleep(1000);
        cf.delete().forPath("/super"); //不触发

        Thread.sleep(Integer.MAX_VALUE);
    }
}

路径为:/super
数据为:123
状态为:4294967599,4294967599,1536825947234,1536825947234,0,0,0,0,3,0,4294967599
---------------------------------------
路径为:/super
数据为:456
状态为:4294967599,4294967600,1536825947234,1536825948248,1,0,0,0,3,0,4294967599
---------------------------------------

监听子节点

public class CuratorWatcher2 {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    public static void main(String[] args) throws Exception {
        //1 重连策略:每隔1s重连一次,重连10次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
        //2 通过工厂创建连接
        CuratorFramework cf = CuratorFrameworkFactory.builder()
                .connectString(CONNECT_ADDR)
                .sessionTimeoutMs(SESSION_OUTTIME)
                .retryPolicy(retryPolicy)
                .build();
        //3 开启连接
        cf.start();

        //4 建立一个PathChildrenCache缓存,第三个参数为是否接受节点数据内容 如果为false则不接受
        PathChildrenCache cache = new PathChildrenCache(cf, "/super", true);
        //5 在初始化的时候就进行缓存监听
        cache.start(StartMode.POST_INITIALIZED_EVENT);
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            /**
             * 方法名称:监听子节点变更
             * 概要说明:新建、修改、删除
             */
            @Override
            public void childEvent(CuratorFramework cf, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                case CHILD_ADDED:
                    System.out.println("CHILD_ADDED :" + event.getData().getPath());
                    break;
                case CHILD_UPDATED:
                    System.out.println("CHILD_UPDATED :" + event.getData().getPath());
                    break;
                case CHILD_REMOVED:
                    System.out.println("CHILD_REMOVED :" + event.getData().getPath());
                    break;
                default:
                    break;
                }
            }
        });

        //创建根节点
        cf.create().forPath("/super", "init".getBytes()); //不触发

        //添加子节点
        Thread.sleep(1000);
        cf.create().forPath("/super/c1", "c1内容".getBytes()); //触发
        Thread.sleep(1000);
        cf.create().forPath("/super/c2", "c2内容".getBytes()); //触发

        //修改子节点
        Thread.sleep(1000);
        cf.setData().forPath("/super/c1", "c1更新内容".getBytes()); //触发

        //删除子节点
        Thread.sleep(1000);
        cf.delete().forPath("/super/c2"); //触发

        //删除本身节点
        Thread.sleep(1000);
        cf.delete().deletingChildrenIfNeeded().forPath("/super"); //触发, 因为级联删除了c1子节点

        Thread.sleep(Integer.MAX_VALUE);
    }
}

CHILD_ADDED :/super/c1
CHILD_ADDED :/super/c2
CHILD_UPDATED :/super/c1
CHILD_REMOVED :/super/c2
CHILD_REMOVED :/super/c1

Curator应用场景

分布式锁

public class Lock {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    static int count = 10;
    public static void genarNo(){
        try {
            count--;
            System.out.println(count);
        } finally {
        }
    }

    public static void main(String[] args) throws Exception {
        //1 重连策略:每隔1s重连一次,重连10次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
        //2 通过工厂创建连接
        CuratorFramework cf = CuratorFrameworkFactory.builder()
                .connectString(CONNECT_ADDR)
                .sessionTimeoutMs(SESSION_OUTTIME)
                .retryPolicy(retryPolicy)
                .build();
        //3 开启连接
        cf.start();

        //4 分布式锁
        final InterProcessMutex lock = new InterProcessMutex(cf, "/super");
        final CountDownLatch countdown = new CountDownLatch(1);

        for(int i = 0; i < 10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        countdown.await();
                        //加锁
                        lock.acquire();
                        //业务处理
                        genarNo();
                        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss|SSS");
                        System.out.println(sdf.format(new Date()));
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            lock.release();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            },"t" + i).start();
        }
        Thread.sleep(100);
        countdown.countDown();
    }
}

count值: 9 - 0

分布式计数器

public class CuratorAtomicInteger {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    public static void main(String[] args) throws Exception {
        //1 重连策略:每隔1s重连一次,重连10次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
        //2 通过工厂创建连接
        CuratorFramework cf = CuratorFrameworkFactory.builder()
                .connectString(CONNECT_ADDR)
                .sessionTimeoutMs(SESSION_OUTTIME)
                .retryPolicy(retryPolicy)
                .build();
        //3 开启连接
        cf.start();

        //4 使用DistributedAtomicInteger
        DistributedAtomicInteger atomicIntger = 
                new DistributedAtomicInteger(cf, "/super", new RetryNTimes(3, 1000));

        //把程序打包在1000台服务器上执行, 最终结果为1000
        AtomicValue value = atomicIntger.add(1);
        System.out.println(value.succeeded()); //操作是否执行成功
        System.out.println(value.postValue()); //add(1)操作之后的值
        System.out.println(value.preValue()); //add(1)操作之前的值
    }
}

分布式障碍

(1)DistributedDoubleBarrier

同步一个操作的开始和结束. n个Client都准备好后才开始执行后续操作. n个Client都执行完后, 才能退出.

public class CuratorBarrier1 {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms

    public static void main(String[] args) throws Exception {
        for(int i = 0; i < 5; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
                        CuratorFramework cf = CuratorFrameworkFactory.builder()
                                    .connectString(CONNECT_ADDR)
                                    .retryPolicy(retryPolicy)
                                    .build();
                        cf.start();
                        DistributedDoubleBarrier barrier = new DistributedDoubleBarrier(cf, "/super", 5);
                        Thread.sleep(1000 * (new Random()).nextInt(3)); 
                        System.out.println(Thread.currentThread().getName() + "已经准备");

                        barrier.enter();
                        System.out.println("同时开始运行...");
                        Thread.sleep(1000 * (new Random()).nextInt(3));
                        System.out.println(Thread.currentThread().getName() + "运行完毕");

                        barrier.leave();
                        System.out.println("同时退出运行...");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            },"t" + i).start();
        }
    }
}

(2)DistributedBarrier

与并发工具类CycleBarrier类似. 客户端对节点设置Barrier, 直到所有Barrier被释放才能对该节点进行操作.

public class CuratorBarrier2 {
    //zookeeper地址
    static final String CONNECT_ADDR = "192.168.1.130:2181";
    //session超时时间
    static final int SESSION_OUTTIME = 5000;//ms
    static DistributedBarrier barrier = null;

    public static void main(String[] args) throws Exception {
        for(int i = 0; i < 5; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
                        CuratorFramework cf = CuratorFrameworkFactory.builder()
                                    .connectString(CONNECT_ADDR)
                                    .sessionTimeoutMs(SESSION_OUTTIME)
                                    .retryPolicy(retryPolicy)
                                    .build();
                        cf.start();

                        barrier = new DistributedBarrier(cf, "/super");
                        System.out.println(Thread.currentThread().getName() + "设置barrier!");

                        barrier.setBarrier(); //设置barrier
                        barrier.waitOnBarrier(); //等待
                        System.out.println("---------开始执行程序----------");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            },"t" + i).start();
        }
        Thread.sleep(5000);
        barrier.removeBarrier(); //释放barrier
    }
}

你可能感兴趣的:(ZooKeeper笔记)