HMZK3【Zookeeper Watch事件监听】

1 概念

image-20221022110404739

image-20221022110437992

  • ZooKeeper 允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。

    • image-20221022110722525
    • 例如上图:用户在服务端的app1节点上注册了Watcher监听器,特殊事件比如节点数据变更,感兴趣的客户端app1会受到通知
  • ZooKeeper 中引入了Watcher机制来实现了发布/订阅功能能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者。

  • ZooKeeper 原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便,需开发人员自己反复注册Watcher,较繁琐。

  • Curator引入了 Cache 来实现对 ZooKeeper 服务端事件的监听。

  • ZooKeeper提供了三种Watcher:

    • NodeCache : 只是监听某一个特定的节点
    • PathChildrenCache : 监控一个ZNode的子节点.
    • TreeCache : 可以监控整个子树上的所有节点,类似于PathChildrenCache和NodeCache的组合
      • 即当前节点及其所有孩子节点;兄弟节点及他们的孩子监控不到

2 实现

2.1NodeCache

image-20221022155030953image-20221022155204562

2.2 PathChildrenCache

image-20221022160103595

image-20221022160614385

image-20221022160811270

节点本身并不能被监听到,只能监听其孩子节点

2.3 TreeCache

image-20221022162434546

2.4 源代码

package com.yppah.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @Author: haifei
 * @Date: 2022/10/22 9:29
 */
public class CuratorWatcherTest {

    private CuratorFramework client3;

    @Before
    public void testConnect() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client3 = CuratorFrameworkFactory.builder()
                .connectString("101.43.128.227:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .namespace("ohh")
                .build();
        //这种命名空间的目录节点,在其下没有任何子节点时,不久该目录节点可能会被自动删除
        client3.start();
    }

    @After
    public void close() {
        if (client3 != null) {
            client3.close();
        }
    }


    /**
     * 给指定一个节点注册监听器
     */
    @Test
    public void testNodeCache() throws Exception {
        // 1、创建NodeCache对象
        final NodeCache nodeCache = new NodeCache(client3, "/app1");
        // 2、注册监听
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了:");
                //获取修改节点后的数据
                byte[] data = nodeCache.getCurrentData().getData();
                String path = nodeCache.getCurrentData().getPath();
                Stat stat = nodeCache.getCurrentData().getStat();
                System.out.println(new String(data));
                System.out.println(path);
                System.out.println(stat);
            }
        });
        // 3、开启监听(如果设置为true,则开启监听时加载缓冲数据)
        nodeCache.start(true);

        //测试用(因为正常运行Test方法会直接结束程序,监听不到变化)
        while (true) {

        }
    }

    /**
     * 监听某节点的所有孩子节点
     */
    @Test
    public void testPathChildrenCache() throws Exception {
        //1、创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client3, "/app2", true);
        //2、绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                System.out.println("子节点变化了:");
                System.out.println(pathChildrenCacheEvent);
                //监听子节点的数据变更,并拿到变更后的数据
                //2-1 获取类型
                PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
                //2-2 判断类型是否为update
                if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
                    System.out.println("数据变化了:");
                    byte[] data = pathChildrenCacheEvent.getData().getData();
                    System.out.println(new String(data));
                }
            }
        });

        //3、开启监听
        pathChildrenCache.start();
        while (true) {

        }
    }

    /**
     * 监听某节点本身及其所有孩子节点
     */
    @Test
    public void testTreeCache() throws Exception {
        //1、创建监听对象
        TreeCache treeCache = new TreeCache(client3, "/app2");
        //2、注册监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                System.out.println("节点变化了:");
                System.out.println(treeCacheEvent);
            }
        });
        //3、开启监听
        treeCache.start();

        while (true) {

        }
    }
}

posted @   yub4by  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示