Zookeeper的watch机制是如何工作的?

news2024/11/23 22:23:04

ZooKeeper Watch 概述

ZooKeeper Watch 机制类似于 Java 设计模式中的观察者模式或者监听模式,唯一的不同是不再基于线程间通信,而是基于进程间通信。

ZooKeeper Watch 机制是指,客户端在所有的读命令上告知服务端:这个节点或者子节点变化时通知我,具体来说,支持的写操作有:

  • getData

  • getChildren

  • exists

例如,我们在命令行可以输入 get -w /foo,其中 -w 参数就是用于告知 ZooKeeper 服务端,当前客户端想在 /foo 节点上设置一个监听器。

注意事项:写操作不支持任何形式的 watch 注册。

另一方面,ZooKeeper 支持的事件监听类型与对应的注册方法有:

  • NodeCreated 节点创建:exits()

  • NodeDataChanged 节点数据改变:exits()getData()

  • NodeDeleted 节点删除:exits()getData()getChildren()

  • NodeChildrenChanged 子节点改变:getChildren()

注意事项:自节点数据的改变并不会引发 NodeChildrenChanged 子节点改变事件。

ZooKeeper Watch 机制的两个细节:

  • wactch 是一次性触发的(除了永久递归 watch),如果客户端需要在一个 watch 通知后继续收到相同节点的 watch 通知,那么必须再次注册 watch 一次

  • 服务端发给客户端的 watch 通知并不包含具体的节点数据,其起到的作用非常存粹:告知客户端其关注的节点发生了 watch 事件

关于 ZooKeeper Watch ,我们需要解决如下模型的实现:

模型如下图所示:

  • 服务端

    • 如何为带有 watch 的读请求进行事件注册;

    • 在节点的写操作发送时,如何触发事件,将事件通知发送给客户端;

  • 客户端

    • 命令的发送、注册用与序列化发送;

    • 事件的监听与回调;

模型如下图所示:

这里的要点是:无论是客户端还是服务端,只有将 Watcher 进行注册,才能在事件发送时进行回调,否则不进行回调。

Watcher实现原理 

client端连接后会注册一个事件,然后客户端会保存这个事件,通过zkWatcherManager保存客户端的事件注册,通知服务端Watcher为true,然后服务端会通过WahcerManager会绑定path对应的事件。如下图:

一个Watcher工作主要包含三步:客户端注册watcher、服务端处理watcher和客户端回调watcher事件。

客户端注册watcher 

在通过客户端接口调用时,可以指定一个watcher接口,以接受服务器事件的回调。在注册watcher接口后,客户端首先会对当前客户端请求request进行标记,将其设置为“使用watcher监听”,同时会封装一个watcher的注册信息watchRegistration对象,用于暂时保存数据数据节点和watcher的对象关系。由于zookeeper中的最小通讯单元为packet,因此,在clientCnxn中watchregistration又会被封装到Packet中,然后放入发送队列中等待客户端发送。随后,客户端会想服务端发送请求,并等待请求返回。完成请求之后,客户端的SendThread线程的readresponse方法负责接收服务端的请求,并将接收到的packet中的watcher注册到ZKWatcherManager中,并最终保存到dataWatchers中,用于服务端事件的回调的时候获取对应节点的对应watcher事件。

用户调用exists/getData/getChildren注册监听以后,会做几个事情

1.将请求数据封装为packet,添加到outgoingQueue队列中

2.SendThread这个线程会执行数据发送操作,主要是将outgoingQueue队列中的数据发送到服务端

3.通过clientCnxnSocket.doTransport(to,pendingQueue,ClientCnxn.this);其中ClientCnxnSocket是zookeeper客户端和服务端的连接通信的封装,有两个具体的实现类ClientCnxnSocketNetty和ClientCnxnSocketNIO;具体使用哪一个类来实现发送,是在初始化过程是在实例化Zookeeper的时候设置的,默认是ClientCnxnSocketNIO这个类

4.基于第3步,最终会在ClientCnxnSocketNetty方法中执行sendPkt将请求的数据包发送到服务端

服务端处理watcher 

其实客户端注册的watcher并不会传递到服务端,只是在客户端进行了watcher的保存,所以服务端接受到watch注册事件之后,需要将该事件进行封装,在服务端也进行保存。

ServerCnxn存储

ServerCnxn是服务端与客户端进行网络交互的一个NIO接口,代表了客户端与服务端的连接。其底层采用netty实现。所以,在接受到注册请求之后,服务端会将ServerCnxn对象和数据阶段路径保存到WatchManager的watchTable和watch2Paths中。方便事件触发时的调用。

watcher触发

当指定的节点发生相关的事件时,通过调用WatchManager的triggerWatch方法触发相关的事件。其通过将节点信息和事件类型进行封装成为watchedevent,并查找到到对应节点的注册的watcher,然后分别调用watcher的回调函数process。而在process函数中其实就是通过封装的ServerCnxn向客户端发送watchedevent数据请求。具体的watcher业务处理则在客户端处理。

客户端回调watcher事件 

SendThread是客户端开启的与服务端建立TCP长连接的线程,它会一直保持连接状态,采用心跳监测的方式确保与服务端的连接存活。

在客户端的SendThread中,当接收到服务端请求之后,会将请求反序列化成watchedevent对象,并将watchedevent对象转换为watcherevent对象,最后将watcherevent对象添加到EventThread线程,完成对watcher的回调。

EventThread是客户端的一个专门处理watcher时间的线程,其保持了一个待处理事件的队列。它根据传递的事件的类型和节点信息,从客户端的ZKWatcherManager中取出相关的watcher,将其添加到EventThread事件队列中,并在去run方法中不断取出watcher事件进行处理。

这里需要注意是:(1)事件注册是一次性的,因为在每次处理事件之后,就会将相应的watcher注册删除;(2)客户端接收到的服务端watcher事件中并不包含事件更改的具体内容,只是告知发生了这样一个watcher事件,所以,客户端在接收到watcher事件之后,需要在回调函数process中对服务端的数据进行重新获取,才能获得更改的具体内容。

ZooKeeper Watch 机制的特性总结

ZooKeeper 的 Watch 有如下几个特性需要注意:

  • 一次性

    无论是服务端还是客户端,一旦一个 Watcher 被触发,ZooKeeper都会将其从相应的存储中移除。因此,开发人员在 Watcher 的使用上要记住的一点是需要反复注册。这样的设计有效地减轻了服务端的压力。试想,如果注册一个 Watcher 之后一直有效,那么,针对那些更新非常频繁的节点,服务端会不断地向客户端发送事件通知,这无论对于网络还是服务端性能的影响都非常大。

    需要注意的是:ZooKeeper 在 3.6.0 版本中引入了永久 Watcher 机制,利用这个机制可以避免反复注册 Watcher。

  • 客户端串行执行

    客户端 Watcher 回调的过程是一个串行同步的过程,这为我们保证了顺序,同时,需要开发人员注意的一点是,千万不要因为一个 Watcher 的处理逻辑影响了整个客户端的 Watcher 回调。

  • 轻量

    WatchedEvent 是 ZooKeeper 整个 Watcher 通知机制的最小通知单元,这个数据结构中只包含三部分内容:通知状态、事件类型和节点路径。也就是说,Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。例如针对 NodeDataChanged 事件,ZooKeeper 的 Watcher 只会通知客户端指定数据节点的数据内容发生了变更,而对于原始数据以及变更后的新数据都无法从这个事件中直接获取到,而是需要客户端主动重新去获取数据。这也是ZooKeeper 的 Watcher机制的一个非常重要的特性。

    另外,客户端向服务端注册 Watcher 的时候,并不会把客户端真实的 Watcher 对象传递到服务端,仅仅只是在客户端请求中使用 boolean 类型属性进行了标记,同时服务端也仅仅只是保存了当前连接的 ServerCnxn 对象。如此轻量的 Watcher 机制设计,在网络开销和服务端内存开销上都是非常廉价的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2077066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows 提权方式汇总

windows 提权 一、土豆(potato)家族提权 原理 土豆提权就是通过 windows 的 COM(Component Object Model,组件对象模型)类。向指定的服务器端口发送 NTLM 认证,捕获认证数据包,并修改数据包内…

【C++】—— 内存管理

【C】—— 内存管理 1 C/C 的内存划分 1.1 C/C 的内存分布1.2 C/C 的内存分布练习 2 C语言 中动态内存管理方式:malloc/calloc/realloc/free3 C 内存管理方式3.1 new / delete 操作内置类型3.2 new 和 delete 操作自定义类型3.2.1 new 和 delete 操作自定义类型基础…

layui栅格布局设置列间距不起作用

layui栅格布局支持设置列间距,只需使用预置类layui-col-space*即可。不过实际使用时却始终看不到效果。   根据layui官网文档的说明,只需要在行所在div元素的class属性中增加layui-col-space*即可出现列间距。如下图所示:   但是实际使用…

【MySQL】MySQL 表的增删改查(进阶)

欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 约束类型 not null 非空 unique 唯一 default 指定默认值 primary key 主键 foreign key 外键 check字句 检查 表设计 确定实体 实体之间的关系 聚合查询 聚合函数…

基于SSM的学生信息管理系统的设计与实现 (含源码+sql+视频导入教程+文档+VISIO图)

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的学生信息管理系统12拥有三种角色:学生、教师、管理员 学生:选课、查看已选课程、查看成绩 教师:成绩管理 管理员:课程管理、学生…

ai变声:视频怎么变音?分享6个语音变声器,视频变声不再难!

想过如何让自己的直播内容更吸引人吗?你是否希望通过变声器来打造独特的声音效果?或者,如何用创意声音提升观众的互动体验呢?随着直播行业的不断发展,每位主播都在努力寻找吸引观众的独特方式,而变声器正是…

【电脑使用耳机录音注意事项】

文章目录 电脑音设置 电脑音设置 打开声音设置:右键小喇叭 → 选择“声音(S)”→选择 “录制”: 选择 “阵列麦克风” 调整声音大小: 音频增强设置

AI大模型编写多线程并发框架(六十二):限流和并发度优化

系列文章目录 文章目录 系列文章目录前言一、项目背景二、第三轮对话-补充异步执行代码三、第四轮对话-增加限流器四、第五轮对话-抽取限流器接口五、第六轮对话-修改并发度三、参考文章 前言 在这个充满技术创新的时代,AI大模型正成为开发者们的新宠。它们可以帮助…

何为MethodHandles?

最近在梳理ThreadPoolExecutor,无意间看到其内部类Worker实现了一个名字叫做AbstractQueuedSynchronizer的抽象类。看到它,我便想起当年为了面试而疯狂学习这个知识点的场景。不过这种临时抱佛脚的行为,并未给我带来即时的收益。也是这次的疯…

基于Java的高校学生工作系统的设计与实现(论文+源码)_kaic

基于Java的高校学生工作系统的设计与实现(论文源码)_kaic 摘 要 本系统为高校学生工作管理系统,系统能够为高校提供便捷的学生信息管理功能。该系统采用 Java 语言编写,系统采用MVC架构进行设计,通过Servlet和JSP等技术实现前后端数据交互和…

【漏洞复现】SuiteCRM responseEntryPoint Sql注入漏洞

免责声明: 本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测…

基于UDS的Flash 刷写——BootLoad刷写流程详解

从0开始学习CANoe使用 从0开始学习车载测试 相信时间的力量 星光不负赶路者,时光不负有心人。 目录 流程概述UDS流程详解释前编程①诊断会话控制 - 切换到扩展会话(10 03)②例程控制-预编程条件检查(31 01 02 03)③DTC…

ClickHouse分布式部署搭建单分片二副本集群

搭建单分片二副本集群,使用MergeTree引擎测试数据同步 服务器: 127.0.0.1 clickhouse 127.0.0.2 clickhouse + keeper 结构图 1.修改hosts vi /etc/hosts 添加需要部署的ip和名字 127.0.0.1 node1 127.0.0.2 node2 2. node1配置文件修改 2.1 修改/etc/clickhouse-se…

Excel中使用VBS自定义函数将中文转为拼音首字母

1、在“开发工具”中&#xff0c;点击“Visual Basic”。如果没有“开发工具”&#xff0c;则添加。 2、添加“模块”&#xff0c;在窗口中添加自定义函数。 Function MyGetPYChar(char) MyCodeNumber 65536 Asc(char) If (MyCodeNumber > 45217 And MyCodeNumber <…

【网络安全】缓存配置错误导致授权绕过

未经许可,不得转载。 文章目录 正文复现正文 一个电子商务网站,它有 2 个资产:target.com和admin.target.com target.com是面向用户的门户,用户可以去那里购买物品。admin.target.com是卖家的管理门户,卖家可以在其中列出他们的物品,跟踪订单、客户信息等。 我正在测试…

有希带你深入理解指针(3)

前言 本篇文章是对指针知识的进一步讲解&#xff0c;如果对部分知识有不了解的地方可以移步前文进行学习&#xff01; 1.字符指针变量 该内容我们在前面的文章中已提到过&#xff0c;想必大家对它应该不陌生吧&#xff01;这里我们会对它进行详细的介绍。 一般情况下&#xf…

FPGA开发——IIC实现简单的串口回环

一、概述 在我们进行日常开发时&#xff0c;不管是进行MCU、单片机、还是FPGA&#xff0c;都会使用到IIC通信协议。采用串行总线可以简化系统硬件结构、减小系统体积、提高系统可靠性。常 用的串行总线有单总线&#xff08;1-Wire Bus&#xff09;、IIC&#xff08;Inter-Integ…

Codeforces Round 926 (Div. 2) C. Sasha and the Casino (博弈论*1400)

这里的意思是想让我们求得是否是能够实现不停地无上限的赚钱。 这里注意避开一个思维误区&#xff0c;如果你想的是前x次一直用1枚硬币然后吃第x1次保底&#xff0c;那么就是错误的。你应该考虑到如果前x次里面出现了胜利呢&#xff1f;这时候你拿着一枚硬币根本赚不回本。 所…

全志H616系统启动和登录

一、系统启动 刷完机烧入镜像&#xff0c;直接用MobaXterm软件串口登陆 约定固定的波特率115200。 默认登录&#xff1a; 用户&#xff1a;orangepi 密码&#xff1a;orangepi 或用户&#xff1a;root 密码&#xff1a;orangepi 在输入密码时…

YOLO 单目测距:原理、方法与代码

一、原理 单目测距的一个常见方法是假设物体的尺寸已知。通过测量物体在图像中的高度&#xff08;或宽度&#xff09;&#xff0c;并结合物体的实际高度&#xff08;或宽度&#xff09;&#xff0c;最简单的一种方式就是利用相似三角形的原理来计算物体的距离。 二、相似三角…