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

2024-08-23 18:52
文章标签 工作 机制 zookeeper watch

本文主要是介绍Zookeeper的watch机制是如何工作的?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 机制设计,在网络开销和服务端内存开销上都是非常廉价的。

这篇关于Zookeeper的watch机制是如何工作的?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1100221

相关文章

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取

MySQL中的锁和MVCC机制解读

《MySQL中的锁和MVCC机制解读》MySQL事务、锁和MVCC机制是确保数据库操作原子性、一致性和隔离性的关键,事务必须遵循ACID原则,锁的类型包括表级锁、行级锁和意向锁,MVCC通过非锁定读和... 目录mysql的锁和MVCC机制事务的概念与ACID特性锁的类型及其工作机制锁的粒度与性能影响多版本

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

Spring使用@Retryable实现自动重试机制

《Spring使用@Retryable实现自动重试机制》在微服务架构中,服务之间的调用可能会因为一些暂时性的错误而失败,例如网络波动、数据库连接超时或第三方服务不可用等,在本文中,我们将介绍如何在Sp... 目录引言1. 什么是 @Retryable?2. 如何在 Spring 中使用 @Retryable

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3