Watcher---Zk事件监听机制和原理

2021-12-22 16:18:50 浏览数 (1)

Zookeeper的Watcher 监听机制是 Zookeeper 中非常重要的特性,很多时候我们之所以用Zookeeper的原因其实都是因为Zookeeper这个特性.

想一想,我其实很久之前貌似做过类似于持续集成自动配置方面的尝试,那时候好像用的是MQ,我的配置改变了后向MQ发个消息,然后客户端的MQ消费者重新拉配置下来进行更新...

一. Zookeeper事件监听机制

我们基于 zookeeper 上创建的节点,可以对这些节点绑定监听事件,比如可以监听节点数据变更、节点删除、子节点状态变更等事件,通过这个事件机制,可以基于 zookeeper实现分布式锁集群管理等功能

watcher 特性当数据发生变化的时候, zookeeper 会产生一个

watcher 事件,并且会发送到客户端。但是客户端只会收到一次

通知。如果后续这个节点再次发生变化,那么之前设置 watcher 的客户端不会再次收到消息。(watcher 是一次性的操作)。

可以通过循环监听去达到永久监听效果.

二 .如何绑定事件机制呢?

以下三个方法均可在使用时候绑定事件.

  • getData
  • Exists
  • getChildren
那么哪些操作会触发事件呢?

如何触发事件? 凡是事务类型的操作,都会触发监听事件。 其实也就是create /delete /setData

三 watcher 事件类型
  • None (-1), 客户端链接状态发生变化的时候,会收到 none 的事件
  • NodeCreated (1), 创建节点的事件。
  • NodeDeleted (2), 删除节点的事件
  • NodeDataChanged (3), 节点数据发生变更
  • NodeChildrenChanged (4); 子节点被创建、被删除、会发生事件触发

举个栗子

代码语言:javascript复制
private static void addEvent(String path) throws KeeperException, InterruptedException {
        zooKeeper.exists(path, new Watcher(){
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("触发事件机制的路径为:" watchedEvent.getPath());
                System.out.println("事件类型为:" watchedEvent.getType());
            }
        });
    }

结果如下图,这也体现了事件的一次性性质,我们明明改变了两次却只触发了一次.

根据人家ZK文档,这里我们加入循环试试,我在添加事件机制在结束的时候,我又再次的为/test结点添加了事件

代码语言:javascript复制
   private static void addEvent(String path) throws KeeperException, InterruptedException {
        zooKeeper.exists(path, new Watcher(){
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("触发事件机制的路径为:" watchedEvent.getPath());
                System.out.println("事件类型为:" watchedEvent.getType());
                //再次为该结点绑定监听,使监听机制有效
                try {
                    zooKeeper.exists(watchedEvent.getPath(),true);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

但是结果如下,我们还是没有监听到事件

那么问题出在哪里呢?实际上,我们在zooKeeper.exists(watchedEvent.getPath(),true);开启的不是exits里自添加的事件,而是走的默认全局事件,我们在创建结点时候添加了一个事件

这里我们验证一下,添加一个全局事件打印

结果如下,验证了我们的猜想

各种操作对应的事件类型

二 . Zookeeper的实现原理

关于watcher事件监听机制,客户端与服务器的大致协调.服务器会受到客户端的命令,使服务器知道哪些Znode开启了事件

watcher源码流程:

源码大致流程

具体源码分析:

首先找到我们添加事件监听机制的方法,比如exists

唤醒触发机制

上面的源码分析我们发现我们只是添加了监听事件的入队,那么出队的消费呢?在哪?

回头我们看一下Zookeeper的构造方法

发现里面启动了俩线程

还有一些判断比如to判断心跳问题

很多很多的判断之后发现最后发现一切正常后,调用传输socket

不论是我们用NIO还是Netty,其消费都是差不多的.我们以Netty为例看下源码.

DoWrite 方法

sendPkt

到此ZK监听机制的客户端部分分析完成!

关于ZK服务器端的watcher机制分析.

跟着某大佬提供的服务端接收请求处理流程总流程,我们看看源码

服务端接收请求处理流程

以后再分析服务端,现在写论文去了.....

0 人点赞