watcher概念

https://zookeeper.apache.org/doc/r3.4.14/zookeeperProgrammers.html#sc_WatchRememberThese

  • zookeeper提供了数据的发布/订阅功能,多个订阅者可同时监听某一特定主题对象,当该主题对象的自身状态发生变化时例如节点内容改变、节点下的子节点列表改变等,会实时、主动通知所有订阅者

  • zookeeper采用了 Watcher机制实现数据的发布订阅功能。该机制在被订阅对象发生变化时会异步通知客户端,因此客户端不必在 Watcher注册后轮询阻塞,从而减轻了客户端压力

  • watcher机制事件上与观察者模式类似,也可看作是一种观察者模式在分布式场景下的实现方式

watcher架构

watcher实现由三个部分组成

  • zookeeper服务端

  • zookeeper客户端

  • 客户端的ZKWatchManager对象

客户端首先将 Watcher注册到服务端,同时将 Watcher对象保存到客户端的watch管理器中。当Zookeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的 Watch管理器会触发相关 Watcher来回调相应处理逻辑,从而完成整体的数据 发布/订阅流程

watcher特性

  • 特性 说明
    一次性 watcher一次性的,一旦被触发就会移除,再次使用时需要重新注册
    客户端顺序回调 watcher回调是顺序串行执行的,只有回调后客户端才能看到最新的数据状态。一个watcher回调逻辑不应该太多,以免影响别的watcher执行
    轻量级 WatchEvent是最小的通信单位,结构上只包含通知状态、事件类型和节点路径,并不会告诉数据节点变化前后的具体内容
    时效性 watcher只有在当前session彻底失效时才会无效,若在session有效期内快速重连成功,则watcher依然存在,仍可接收到通知;

watcher接口设计

Watcher是一个接口,任何实现了Watcher接口的类就算一个新的WatcherWatcher内部包含了两个枚举类:KeeperStateEventType

Watcher通知状态(KeeperState)

KeeperState是客户端与服务端连接状态发生变化时对应的通知类型。路径为org.apache.zookeeper.Watcher.EventKeeperState,是一个枚举类,其枚举属性如下:

  • 枚举属性 说明
    SyncConnected 客户端与服务器正常连接时
    Disconnected 客户端与服务器断开连接时
    Expired 会话session失效时
    AuthFailed 身份认证失败时
Watcher事件类型(EventType)

EventType数据节点znode发生变化时对应的通知类型。EventType变化时KeeperState永远处于SyncConnected通知状态下;当keeperState发生变化时,EventType永远为None。其路径为org.apache.zookeeper.Watcher.Event.EventType,是一个枚举类,枚举属性如下:

  • 枚举属性 说明
    None
    NodeCreated Watcher监听的数据节点被创建时
    NodeDeleted Watcher监听的数据节点被删除时
    NodeDataChanged Watcher监听的数据节点内容发生更改时(无论数据是否真的变化)
    NodeChildrenChanged Watcher监听的数据节点的子节点列表发生变更时
  • 注意:客户端接收到的相关事件通知中只包含状态以及类型等信息,不包含节点变化前后的具体内容,变化前的数据需业务自身存储,变化后的数据需要调用get等方法重新获取

捕获相应的事件

上面讲到zookeeper客户端连接的状态和zookeeperznode节点监听的事件类型,下面我们来讲解如何建立zookeeperwatcher监听。在zookeeper中采用zk.getChildren(path,watch)、zk.exists(path,watch)、zk.getData(path,watcher,stat)这样的方式来为某个znode注册监听 。

下表以node-x节点为例,说明调用的注册方法和可用监听事件间的关系:

注册方式 created childrenChanged Changed Deleted
zk.exists("/node-x",watcher) 可监控   可监控 可监控
zk.getData("/node-x",watcher)     可监控 可监控
zk.getChildren("/node-x",watcher)   可监控   可监控

注册watcher的方法

客户端与服务器端的连接状态
  • KeeperState:通知状态

  • SyncConnected:客户端与服务器正常连接时

  • Disconnected:客户端与服务器断开连接时

  • Expired:会话session失效时

  • AuthFailed:身份认证失败时

  • 事件类型为:None

    

public class ZkConnectionWatcher implements Watcher {
@Override
public void process(WatchedEvent watchedEvent) {
Event.KeeperState state = watchedEvent.getState();
if(state == Event.KeeperState.SyncConnected){
// 正常
System.out.println("正常连接");
}else if (state == Event.KeeperState.Disconnected){
// 可以用Windows断开虚拟机网卡的方式模拟
// 当会话断开会出现,断开连接不代表不能重连,在会话超时时间内重连可以恢复正常
System.out.println("断开连接");
}else if (state == Event.KeeperState.Expired){
// 没有在会话超时时间内重新连接,而是当会话超时被移除的时候重连会走进这里
System.out.println("连接过期");
}else if (state == Event.KeeperState.AuthFailed){
// 在操作的时候权限不够会出现
System.out.println("授权失败");
}
countDownLatch.countDown();
}
private static final String IP = "192.168.133.133:2181"
;
private static CountDownLatch countDownLatch = new CountDownLatch(1); public static void main(String[] args) throws Exception {
// 5000为会话超时时间
ZooKeeper zooKeeper = new ZooKeeper(IP, 5000, new ZkConnectionWatcher());
countDownLatch.await();
// 模拟授权失败
zooKeeper.addAuthInfo("digest1","itcast1:123451".getBytes());
byte[] data = zooKeeper.getData("/hadoop", false, null);
System.out.println(new String(data));
TimeUnit.SECONDS.sleep(50);
}
}
watcher检查节点

exists

  • exists(String path, boolean b)

  • exists(String path, Watcher w)

  • NodeCreated节点创建

  • NodeDeleted节点删除

  • NodeDataChanged节点内容

  

public class EventTypeTest {
private static final String IP = "192.168.133.133:2181";
private static CountDownLatch countDownLatch = new CountDownLatch(1);
private static ZooKeeper zooKeeper; // 采用zookeeper连接创建时的监听器
public static void exists1() throws Exception{
zooKeeper.exists("/watcher1",true);
}
// 自定义监听器
public static void exists2() throws Exception{
zooKeeper.exists("/watcher1",(WatchedEvent w) -> {
System.out.println("自定义" + w.getType());
});
}
// 演示使用多次的监听器
public static void exists3() throws Exception{
zooKeeper.exists("/watcher1", new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
System.out.println("自定义的" + watchedEvent.getType());
} finally {
try {
zooKeeper.exists("/watcher1",this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
// 演示一节点注册多个监听器
public static void exists4() throws Exception{
zooKeeper.exists("/watcher1",(WatchedEvent w) -> {
System.out.println("自定义1" + w.getType());
});
zooKeeper.exists("/watcher1", new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
try {
System.out.println("自定义2" + watchedEvent.getType());
} finally {
try {
zooKeeper.exists("/watcher1",this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
// 测试
public static void main(String[] args) throws Exception {
zooKeeper = new ZooKeeper(IP, 5000, new ZKWatcher());
countDownLatch.await();
exists4();
TimeUnit.SECONDS.sleep(50);
} static class ZKWatcher implements Watcher{
@Override
public void process(WatchedEvent watchedEvent) {
countDownLatch.countDown();
System.out.println("zk的监听器" + watchedEvent.getType());
}
} }

getData

  • getData(String path, boolean b, Stat stat)

  • getData(String path, Watcher w, Stat stat)

  • NodeDeleted节点删除

  • NodeDataChange节点内容发生变化

getChildren

  • getChildren(String path, boolean b)

  • getChildren(String path, Watcher w)

  • NodeChildrenChanged子节点发生变化

  • NodeDeleted节点删除

4、zookeeper的事件监听机制的更多相关文章

  1. 4.JAVA之GUI编程事件监听机制

    事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...

  2. .NET事件监听机制的局限与扩展

    .NET中把“事件”看作一个基本的编程概念,并提供了非常优美的语法支持,对比如下C#和Java代码可以看出两种语言设计思想之间的差异. // C#someButton.Click += OnSomeB ...

  3. 关于事件监听机制的总结(Listener和Adapter)

    记得以前看过事件监听机制背后也是有一种设计模式的.(设计模式的名字记不清了,只记得背后实现的数据结构是数组.) 附上事件监听机制的分析图: 一个事件源可以承载多个事件(只要这个事件源支持这个事件就可以 ...

  4. GUI编程笔记(java)05:GUI事件监听机制原理和举例说明

    1.事件监听机制:       A:事件源          事件发生的地方       B:事件             就是要发生的事情       C:事件处理       就是针对发生的事情做 ...

  5. JAVA事件监听机制学习

    //事件监听机制 import java.awt.*; import java.awt.event.*; public class TestEvent { public static void mai ...

  6. Java中的事件监听机制

    鼠标事件监听机制的三个方面: 1.事件源对象: 事件源对象就是能够产生动作的对象.在Java语言中所有的容器组件和元素组件都是事件监听中的事件源对象.Java中根据事件的动作来区分不同的事件源对象,动 ...

  7. java Gui编程 事件监听机制

    1.     GUI编程引言 以前的学习当中,我们都使用的是命令交互方式: 例如:在DOS命令行中通过javac java命令启动程序. 软件的交互的方式:   1. 命令交互方式    图书管理系统 ...

  8. Java swing(awt):事件监听机制的实现原理+简单示例

    (1)实现原理 事件监听机制的实现: 参考图:事件模型_ActionEvent 为了节省资源,系统无法对某个事件进行实时的监听.故实现的机制是当发生某个事件后,处理代码将被自动运行,类似钩子一般.(回 ...

  9. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  10. 简单剖析Node中的事件监听机制(一)

    使用js的class类简单的实现一个事件监听机制,不同于浏览器中的时间绑定与监听,类似于node中的时间监听,并且会在接下来的文章中去根据自己的理解去写一下Event模块中的原理. Node.js使用 ...

随机推荐

  1. MySQL 字符串与时间操作函数

    MariaDB [lyshark]> select Name,char_length(Name) from lyshark; -- 求字符串长度 +------------+---------- ...

  2. C/C++ Qt 使用JSON解析库 [修改篇]

    JSON是一种轻量级的数据交换格式,它是基于ECMAScript的一个子集,使用完全独立于编程语言的文本格式来存储和表示数据,简洁清晰的的层次结构使得JSON成为理想的数据交换语言,Qt库为JSON的 ...

  3. 植物大战僵尸:寻找阳光掉落Call

    本次实验内容:本次实验将接触到Call调用这个概念,什么是Call调用? Call相当于你在编程时所编写的函数,而高级语言中的函数最终也是会被编译器转换为汇编格式的Call调用,这些关键Call普遍都 ...

  4. AnyCAD程序无法启动的问题解决方法

    在某些电脑上会出现基于AnyCAD开发的程序无法启动的问题,如: System-ArgumentEcception: Please check the dependendes 解决方法 安装最新的VS ...

  5. Xcode常用环境变量与常见使用场景

    在Xcode的工程配置中,与路径相关的都是使用环境变量,这样可以避免使用决定路径时项目移植性差的问题. Xcode常用宏 __FILE__ 当前文件所在目录 __DATE__ 编译日期的字符串,格式为 ...

  6. PHP基础题目

    1.请写一个函数实现以下功能:字符串'open_door'转换成'OpenDoor','make_by_id'转换成'MakeById' function strHandle($str) { $ret ...

  7. 教你用JavaScript获取大转盘

    案例介绍 欢迎来到我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript编程实战案例,做一个大转盘.当你难以抉择的时候不妨用这个案例来帮你做选择.通过编程实战我们可以学到按钮的 ...

  8. (Python)每日代码||2024.1.17||函数中给列表形参默认值时,该默认列表在函数中的改变会保留下来

    def f(x,li=[1]): print(id(li)) li.append(x) print(li) f('a')#第一次调用函数 print() f('b')#第二次调用函数 print() ...

  9. ABC270F 题解

    和博客园一样好的体验 思路 首先看到花最小代价使得所有点连通,果断转换成最小生成树问题. 接下来就要考虑怎么建图,首先陆地就正常连不用说,建机场和港口的代价貌似都是点权,考虑转成边权.因为一个点飞或者 ...

  10. 小知识:Oracle中的层次查询

    使用Oracle中的start with .. connect by prior ..语句可以轻松实现. 下面通过scott用户下的emp来做演示,使用自己的一个19c测试环境,结果发现默认并没有sc ...