【弄nèng - Zookeeper】Zookeeper入门教程(四)—— 事件通知cache(Curator-recipes)

本文介绍zk客户端curator的使用,本文主要介绍Curator recipes的使用
官方文档传送门
官方文档Curator recipes
参考:http://www.throwable.club/2018/12/16/zookeeper-curator-usage/
参考书籍:《从Paxos到ZooKeeper 分布式一致性原理与实践》

1. Curator-recipes简介

官网传送门
Curator recipes 提供了一些高级特性,包括领导人选举,共享锁,路径缓存和观察者,分布式队列,分布式优先级队列等等。

pom

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

2. 事件监听

Zookeeper原生支持通过注册Watcher来进行事件监听,但是并不方便,反复开发者反复注册Watcher。Cache是Curator中对事件监听的包装,可以看作是对事件监听的本地缓存视图,能够自动为开发者处理反复注册监听。Curator提供了三种Watcher Cache来监听结点的变化。

Cache

类型 描述
NodeCache 尝试保留本地缓存的节点中的数据。此类将监视节点,响应更新/创建/删除事件,下拉数据等。您可以注册一个侦听器,当发生更改时,该侦听器将得到通知。
PathChildrenCache 路径缓存用于监视ZNode。每当添加,更新或删除子项时,路径缓存都会更改其状态以包含当前子项集,子项数据和子项状态。Curator框架中的路径缓存由PathChildrenCache类提供。对路径的更改将传递到已注册的PathChildrenCacheListener实例。
TreeCache 尝试保留本地缓存的ZK路径的所有子级中的所有数据。此类将监视ZK路径,响应更新/创建/删除事件,拉下数据,等等。您可以注册一个侦听器,当发生更改时它会得到通知。

2.1 NodeCache

用于监听数据节点的变更。尝试保留本地缓存的节点中的数据。此类将监视节点,响应更新/创建/删除事件,下拉数据等。您可以注册一个侦听器,当发生更改时,该侦听器将得到通知。

事例

	/**
     * NodeCache
     */
    @Test
    public void nodeCache() throws Exception {
        String path = "/node-cache";
        // 创建节点并赋值
        client.create()
                .creatingParentsIfNeeded()
                .withMode(CreateMode.EPHEMERAL)
                .forPath(path, "sima".getBytes());
        // 参数3:是否对数据进行压缩
        final NodeCache cache = new NodeCache(client, path, false);
        // 参数1:默认false,如果设置true代表第一次启动的时候从ZK上读取对应节点的数据内容
        cache.start(true);
        cache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                // getCurrentData()得到节点当前的状态
                ChildData data = cache.getCurrentData();
                if (null != data) {
                    System.out.println("节点数据更新:" + new String(data.getData()));
                } else {
                    System.out.println("节点被删除");
                }
            }
        });
        // 更新数据
        client.setData().forPath(path, "gang".getBytes());
        Thread.sleep(1000);
        // 删除节点
        client.delete().deletingChildrenIfNeeded().forPath(path);
        Thread.sleep(Integer.MAX_VALUE);

       /* cache.close();
        client.close();*/
    }

使用完cache记得close()

控制台
在这里插入图片描述

2.2 PathChildrenCache

路径缓存用于监视数据节点的子节点的变化。每当添加,更新或删除子项时,路径缓存都会更改其状态以包含当前子项集,子项数据和子项状态。Curator框架中的路径缓存由PathChildrenCache类提供。对路径的更改将传递到已注册的PathChildrenCacheListener实例。

2.2.1 事例

	/**
     * PathChildrenCache
     */
    @Test
    public void pathChildrenCache() throws Exception {
        String path = "/path-cache1";
        // 参数3:缓存节点内容,如果设置true,那么客户端在接收到节点列表变更的同时,也能够获取节点的数据内容
        // 参数4(可选):threadFactory和executorService可以使用单独的线程池来处理事件通知
        PathChildrenCache cache = new PathChildrenCache(client, path, true);
        // 启动模式:
        // NORMAL: 初始化缓存数据为空
        // BUILD_INITIAL_CACHE: 在start方法返回前,初始化获取每个子节点数据并缓存
        // POST_INITIALIZED_EVENT: 在后台异步初始化数据完成后,会发送一个INITIALIZED初始化完成事件
        cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                	// 初始化
                    // case INITIALIZED:
                    //    System.out.println("INITIALIZED," + event.getData().getPath());
                    //    break;
                    
                    // 添加子节点
                    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;
                }
            }
        });
        // 创建节点
        client.create().withMode(CreateMode.PERSISTENT).forPath(path);
        Thread.sleep(1000);
        // 创建子节点
        client.create().withMode(CreateMode.PERSISTENT).forPath(path + "/z2");
        Thread.sleep(1000);
        // 删除子节点
        client.delete().forPath(path + "/z2");
        Thread.sleep(1000);
        // 删除节点
        client.delete().forPath(path);
        Thread.sleep(Integer.MAX_VALUE);
    }

注意

  1. curator无法对当前节点和二级子节点进行监听
  2. PathChildrenCache在调用start()方法时,有3种启动模式,分别为NORMAL,BUILD_INITIAL_CACHE,POST_INITIALIZED_EVENT
  3. POST_INITIALIZED_EVENT状态event.getData()返回值为null

控制台
在这里插入图片描述

2.2.1 带线程参数事例

	/**
     * PathChildrenCache--带线程池
     */
    @Test
    public void pathChildrenCacheWithThread() throws Exception {
        String path = "/path-cache1";
        ExecutorService ex = Executors.newFixedThreadPool(2);
        // 参数3:缓存节点内容,如果设置true,那么客户端在接收到节点列表变更的同时,也能够获取节点的数据内容
        // 参数4(可选):threadFactory和executorService可以使用单独的线程池来处理事件通知
        PathChildrenCache cache = new PathChildrenCache(client, path, true, false, ex);
        // 启动模式:
        // NORMAL: 初始化缓存数据为空
        // BUILD_INITIAL_CACHE: 在start方法返回前,初始化获取每个子节点数据并缓存
        // POST_INITIALIZED_EVENT: 在后台异步初始化数据完成后,会发送一个INITIALIZED初始化完成事件
        cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                    // 初始化
                    case INITIALIZED:
                        System.out.println("INITIALIZED," + event.getData().getPath());
                        break;
                    // 添加子节点
                    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;
                }
            }
        });
        // 创建节点
        client.create().withMode(CreateMode.PERSISTENT).forPath(path);
        Thread.sleep(1000);
        // 创建子节点
        client.create().withMode(CreateMode.PERSISTENT).forPath(path + "/z2");
        Thread.sleep(1000);
        // 删除子节点
        client.delete().forPath(path + "/z2");
        Thread.sleep(1000);
        // 删除节点
        client.delete().forPath(path);
        Thread.sleep(Integer.MAX_VALUE);
    }

2.3 TreeCache

监听路径下所有节点的变化,相当于NodeCache+PathChildrenCache,尝试保留本地缓存的ZK路径的所有子级中的所有数据。此类将监视ZK路径,响应更新/创建/删除事件,拉下数据,等等。您可以注册一个侦听器,当发生更改时它会得到通知。

事例

	/**
     * TreeCache
     */
    @Test
    public void TreeCache() throws Exception {
        String path = "/tree-cache";
        // 创建节点
        client.create().creatingParentsIfNeeded().forPath(path);
        TreeCache cache = new TreeCache(client, path);
        TreeCacheListener listener = (client1, event) ->
                System.out.println("事件类型:" + event.getType() +
                        ",路径:" + (null != event.getData() ? event.getData().getPath() : null));
        cache.getListenable().addListener(listener);
        cache.start();
        // 更新数据
        client.setData().forPath(path, "1".getBytes());
        Thread.sleep(1000);
        // 更新数据
        client.setData().forPath(path, "2".getBytes());
        Thread.sleep(1000);
        // 删除节点
        client.delete().deletingChildrenIfNeeded().forPath(path);
        Thread.sleep(1000 * 2);
        cache.close();
        client.close();
    }

注意:TreeCache在调用start()的时候会回调TreeCacheListener实例一个TreeCacheEvent,而回调的TreeCacheEvent对象的Type为INITIALIZED,ChildData为null,此时event.getData().getPath()可能导致空指针异常,需要我们主动处理并避免这种情况

控制台
在这里插入图片描述

3. Curator recipes

官网传送门
Curator recipes 提供了一些高级特性,包括领导人选举,共享锁,路径缓存和观察者,分布式队列,分布式优先级队列等等。

源码地址

IT-CLOUD-ZOOKEEPER :zookeeper客户端Curator事例


项目推荐

IT-CLOUD :IT服务管理平台,集成基础服务,中间件服务,监控告警服务等。
IT-CLOUD-ACTIVITI6 :Activiti教程源码。博文在本CSDN Activiti系列中。
IT-CLOUD-ELASTICSEARCH :elasticsearch教程源码。博文在本CSDN elasticsearch系列中。
IT-CLOUD-KAFKA :spring整合kafka教程源码。博文在本CSDN kafka系列中。
IT-CLOUD-KAFKA-CLIENT :kafka client教程源码。博文在本CSDN kafka系列中。
IT-CLOUD-ZOOKEEPER :zookeeper客户端Curator事例。博文在本CSDN zookeeper系列中。

开源项目,持续更新中,喜欢请 Star~

发布了178 篇原创文章 · 获赞 48 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/yy756127197/article/details/105214871