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机制分析.
跟着某大佬提供的服务端接收请求处理流程总流程,我们看看源码
服务端接收请求处理流程
以后再分析服务端,现在写论文去了.....