Zookeeper核心原理:节点类型、Watcher监听和AsyncCallback异步回调

2 篇文章 0 订阅
1 篇文章 0 订阅

一、zookeeper节点类型:

PERSISTENT:持久化节点
PERSISTENT_SEQUENTIAL:持久化顺序节点
EPHEMERAL:临时节点
EPHEMERAL_SEQUENTIAL:临时顺序节点

持久化节点:一经创建,除非客户端手动删除,否则永久存在,持久化节点可以继续创建子节点。

在这里插入图片描述

持久化顺序节点:在持久化节点的基础上,zookeeper会自动为顺序节点后添加一个递增的序号。

在这里插入图片描述

临时节点:生命周期和客户端会话Session相同,且临时节点不能创建子节点,客户端连接断开后,服务器立即删除该节点或保留临时节点一小段时间,由客户端指定的sessionTimeout决定,目的是防止客户端由于网络波动导致临时节点被删除,通常是2~4s。

在这里插入图片描述

临时顺序节点:在临时节点的基础上,为每个节点添加一个递增的序号

在这里插入图片描述

这时候/lock目录下的节点如下,可以看到有3个持久化顺序节点和一个临时节点,还有两个临时顺序节点。
所有节点

这时候我们运行:quit命令退出客户端。
在这里插入图片描述

再重新连接客户端:

zkCli.sh -server localhost:2181

再查看 /lock 节点下的子节点:

在这里插入图片描述

可以看到,只剩下3个持久化顺序节点,而另外3个临时节点已经自动删除。

二、Zookeeper的Watcher监听:

  1. 监听某个节点的变化。
  2. 一个监听器只会被触发一次。
  3. 一个节点可以注册多个Watcher监听,当这个节点发生事件时,会依次触发所有监听该节点的监听器。
  4. 同一个Watcher实例,对同一个节点,只能注册一次监听,注册多次只会触发一次,而不会触发多次。
  5. 每个Watcher监听都有一个核心方法:
//该方法在收到回调事件的时候会执行 
public void process(WatchedEvent event){
     //节点路径
     String path = event.getPath();
     //事件类型
     Event.EventType eventType = event.getType();
     //客户端状态
     Event.KeeperState eventState = event.getState();
}

其中方法的参数:(WatchedEvent event)作为回调方法的参数,在回调方法执行时被传入,其中最核心的三个属性分别为:

  1. path:监听的节点路径

  2. Event.EventType:Watcher触发的事件类型

    Event.EventType描述
    None客户端连接状态发生改变,也就是Event.KeeperState发生了变化
    NodeCreated节点创建了
    NodeDeleted节点被删除了
    NodeDataChanged节点数据发生改变了
    NodeChildrenChanged节点的子节点发生改变了
  3. Event.KeeperState:客户端状态

    Event.KeeperState描述
    Disconnected客户端断开连接
    SyncConnected客户端连接成功
    AuthFailed客户端身份验证失败
    ConnectedReadOnly客户端以只读的方式连接
    SaslAuthenticated客户端身份验证通过
    Expired客户端过期

三、怎么设置Watcher监听:

1.可以通过客户端的getData()、exists()、getChildren()方法设置。

    //判断节点是否存在并注册一个Watcher监听
    @Test
    void exist2() throws InterruptedException, KeeperException {
        //判断节点是否存在,并注册监听事件,注意:一个监听事件只能触发一次,如果需要多次触发
        //需要第一个监听事件触发后再注册一个监听事件
        Stat exists = zkClient.exists("/lock/e-node", new Watcher() {
            //如果该节点发生变化,比如创建,或者删除时,就会回调该方法
            @Override
            public void process(WatchedEvent event) {
                //节点路径
                String path = event.getPath();
                //事件类型
                Event.EventType eventType = event.getType();
                //客户端状态
                Event.KeeperState eventState = event.getState();
                switch (eventType) {
                    case None:
                        System.out.println("客户端连接状态发生改变");
                        break;
                    case NodeCreated:
                        System.out.println(path+"节点创建了");
                        break;
                    case NodeDeleted:
                        System.out.println(path+"节点删除了");
                        break;
                    case NodeDataChanged:
                        System.out.println(path+"节点数据发生改变了");
                        break;
                    case NodeChildrenChanged:
                        System.out.println(path+"节点的子节点发生改变了");
                        break;
                }
                switch (eventState) {
                    case Disconnected:
                        System.out.println("客户端断开连接");
                        break;
                    case SyncConnected:
                        System.out.println("客户端连接成功");
                        break;
                    case AuthFailed:
                        System.out.println("客户端身份验证失败");
                        break;
                    case ConnectedReadOnly:
                        System.out.println("客户端以只读连接");
                        break;
                    case SaslAuthenticated:
                        System.out.println("客户端身份验证通过");
                        break;
                    case Expired:
                        System.out.println("客户端过期");
                        break;
                }
            }
        });

        //程序休眠一段时间,否则程序结束后就收不到回调信息
        Thread.sleep(300000);
    }

四、Zookeeper异步API调用:AsyncCallback

zookeeper客户端的api分为两种:一种是同步,一种是异步

同步API:很好理解,调用同步api后,主线程处于阻塞状态,等待zk返回结果后,客户端才能继续执行。

异步API:跟同步API相反,客户端调用完后,不需要等待zk返回结果,客户端继续执行后面的代码,但是需要设置一个AsyncCallback回调,当zk服务器返回结果后,会回调客户端注册的这个AsyncCallback中的processResult()方法。来处理返回结果。

AsyncCallback类型:

类型描述使用场景/对应异步api
StatCallback用于获取节点的状态exists()、setData()
DataCallback用于获取节点的数据和状态getData()、
ACLCallback用于获取节点的ACL和状态getACL()
ChildrenCallback用于获取节点的子节点getChildren()
Children2Callback用于获取节点的子节点和状态getChildren()
StringCallback只返回节点的名称create()
VoidCallback空回调,不会返回任何数据delete()、sync()
MultiCallback用于处理有多个结果的回调multi()、multiInternal()

例子:

   //获取节点数据:同步
    @Test
    void getData() {
        String data = zkApi.getData("/node1", new WatcherApi());
        System.out.println("/test1=="+data);

    }
    //获取节点数据:异步
    @Test
    void getAsyncData() throws InterruptedException {
        zkClient.getData("/node2", false, new AsyncCallback.DataCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
                System.out.println("异步回调方法获取的数据:"+path+":"+data);
            }
        },111);
		//主线程休眠,等待回调方法执行
        Thread.sleep(30000);
    }

    //判断节点是否存在:同步
    @Test
    void exist0() throws InterruptedException, KeeperException {

        //调用同步api
        Stat stat = zkClient.exists("/node3", false);
        System.out.println("节点状态:"+stat);

    }

	//判断节点是否存在:异步
    @Test
    void exist() throws InterruptedException {
        //监听器
        MyWatcher myWatcher = new MyWatcher();
        //调用异步api
        zkClient.exists("/node4", false, new AsyncCallback.StatCallback() {
            //调如果zookeeper服务器返回结果,会回调该方法
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                System.out.println("节点状态stat:"+stat);
            }
        },"上下文");

        System.out.println("主线程等待zk服务器返回结果");
        //主线程阻塞,等待回调
        Thread.sleep(600000);
    }	

五、Watcher和AsyncCallback的区别:

1.都是异步回调的方式。

2.Watcher关注的是节点的状态变化,AsyncCallback关注的是API调用返回结果,一个是监听节点将来的变化,一个是获取节点当前的状态或数据,所以两者并不冲突,也可以共存。

 	//watcher和AsyncCallback共存
    @Test
    public void watcherAndCallback() throws InterruptedException {

        //使用异步api判断节点是否存在,并注册一个Watcher监听
        zkClient.exists("/test-node", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.getPath() + "节点事件:" + event.getType());
            }
        }, new AsyncCallback.StatCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                System.out.println(path + "节点状态:" + stat);
            }
        }, "上下文");

        //主线程休眠1分钟等待回调
        Thread.sleep(60000);
    }

执行结果:

/test-node节点状态:null
/test-node节点事件:NodeCreated

在这个方法中调用了异步API获取节点是否存在,程序运行后,AsyncCallback立马收到了服务端的返回结果null,说明当前节点不存在,紧接着立马通过linux下启动的zookeeper客户端create /test-node 111创建该节点,然后Watcher监听器立马监听到了该节点的创建事件。

本文中的zkClient来自spring自动注入

	@Autowired
    ZooKeeper zkClient;

	@Bean(name = "zkClient")
    public ZooKeeper zkClient(){
        ZooKeeper zooKeeper=null;
        try {
            final CountDownLatch countDownLatch = new CountDownLatch(1);
            //连接成功后,会回调Watcher中的process()方法,所以先通过CountDownLatch()让线程处于阻塞状态
            // ,等待服务器的异步回调
            zooKeeper = new ZooKeeper(address, sessionTimeout, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if(Event.KeeperState.SyncConnected==event.getState()){
                        //如果服务器返回"已连接"状态,说明客户端连接成功
                        countDownLatch.countDown();
                    }
                }
            });
            countDownLatch.await();
            logger.info("ZooKeeper初始化状态:{}",zooKeeper.getState());
        }catch (Exception e){
            logger.error("ZooKeeper连接异常:{}",e);
        }
        return  zooKeeper;
    }
     

参考:https://blog.csdn.net/u010391342/article/details/100404588

…END…
推荐文章:
Zookeeper小白必看
教你最快速搭建你的Zookeeper集群

如果觉得文章对你有帮助的话,可以微信关注我的公众号:码农小诚
关注我的公众号更多技术文章分享实时更新,与你共同成长,回复【555】还有55本java技术书籍,免费送,回复【zk】还能获取更多zookeeper相关技术书籍。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小诚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值