Zookeeper之快速入门

前言

本篇文章主要还是让人快速上手入门,想要深入的话可以通过书籍系统的学习。

简介

是什么

可用于协调、构建分布式应用。

本质上是一个分布式的小文件存储系统。提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理。从而用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理。

ZooKeeper 适用于存储和协同相关的关键数据,不适合用于大数据量存储。

应用场景

  • 配置中心
  • 注册中心
  • 分布式锁
  • 分布式队列
  • 负载均衡器
  • DNS服务
  • Master选举

安装

  • 下载地址:https://zookeeper.apache.org/releases.html

  • 创建数据存储目录

image.png

  • 拷贝zoo_sample.cfg并重命名为zoo_.cfg,打开并配置数据存储目录

image.png

  • 启动服务器和客户端

image.png

基础概念

存储模型

类似于文件系统的结构。

Zookeeper 的层次模型称作DataTree。DataTree 的每个节点叫作znode。不同于文件系统,每个节点都可以保存数据。每个节点都有一个版本(version),版本从0 开始计数。
DataTree

节点的分类

是否持久?

  • 持久性的:持久化到磁盘。
  • 临时性的:保存在内容中,Server宕机、Client超时未跟Server连接都会丢失(客户端关闭节点也消失)。

是否有序?

  • 持久有序的。
  • 临时有序的。

每个顺序节点,都分配一个唯一且是在之前基础上递增的整数。

客户端命令

帮助help

查询路径下的节点ls

查看根节点:ls /
查看子节点:ls /app1

创建节点

  • 普通节点

create /app1

  • 顺序节点

create -s /app2

  • 临时节点

create -e /app3

  • 临时有序节点

create -e -s /app4

查看节点

查询节点数据

get /app1

节点状态

stat /app1

## -------------------------节点的状态信息,也称为stat结构体---------------------
cZxid = 0x17f ## 该数据节点被创建时的事务id
#其中zxid表示的是zookeeper的事务ID,由64位数字组成,分为高32位和低32位
ctime = Sat Dec 21 19:47:36 CST 2019 ## 该数据节点创建时间
mZxid = 0x17f ## 该数据节点被修改时最新的事物id
mtime = Sat Dec 21 19:47:36 CST 2019 ## 该数据节点最后更新时间
pZxid = 0x183 ## 当前节点的父级节点事务ID
cversion = 4 ## znode子节点变化号,znode子节点修改次数
dataVersion = 0 ## znode数据变化号
aclVersion = 0 ## 访问控制列表的变化号 access control
ephemeralOwner = 0x0 ## 如果临时节点,表示当前节点的拥有者的sessionId。如果不是临时节点,则值为0
dataLength = 6 ## 数据长度
numChildren = 4 ## 子节点数据

修改、删除节点

  • 修改

set /app1 12345

  • 删除

delete /app20000000002

  • 删除多层节点

deleteall /app1

拥有子节点的父节点,无法使用delete删除

案例:使用JAVA API操作ZK

依赖
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.8</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>4.0.0</version><exclusions><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.0</version><exclusions><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.0</version></dependency>
创建节点
  • 创建连接对象
    @Beforepublic void initClient() {//初始化Zookeeper的客户端对象clientString connectString = "127.0.0.1:2181";RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 100);int sessionTimeoutMs = 60 * 1000;//当前客户端会话超时时间int connectionTimeoutMs = 15 * 1000;//连接超时时间client = CuratorFrameworkFactory.newClient(connectString, sessionTimeoutMs,connectionTimeoutMs, retryPolicy);}@Afterpublic void destroy() {client.close();}
  • 创建节点
@Afterpublic void destroy() {client.close();}@Testpublic void createNode() throws Exception {//3种方式,四种节点类型client.start();//方式1: 创建空节点
//        client.create().forPath("/app3");//方式2: 创建有内容节点
//        client.create().forPath("/app4", "app3Node".getBytes());//方式3: 创建多层节点
//        client.create().creatingParentsIfNeeded().forPath("/app5/a", "aa".getBytes());//节点节点类型1 : 持久节点                   CreateMode.PERSISTENT//节点节点类型2 : 临时节点【客户端关闭则节点消失】CreateMode.EPHEMERAL
//        client.create().withMode(CreateMode.EPHEMERAL).forPath("/app6", "app5Node".getBytes());//节点节点类型3 : 持久节点+自带序号 CreateMode.PERSISTENT_SEQUENTIAL
//        client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/app7", "app6Node".getBytes());//节点节点类型4 : 临时节点+自带序号【客户端关闭则节点消失】CreateMode.EPHEMERAL_SEQUENTIAL
//        client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/app8", "app6Node".getBytes());//Thread.sleep(9000);//休眠9秒,观察效果//3.关闭客户端,释放资源client.close();}
修改节点数据
    @Testpublic void updateNode() throws Exception {client.start();client.setData().forPath("/app1", "app1Node".getBytes());client.close();}
查询节点数据
    @Testpublic void getNode() throws Exception {//1.开启客户端client.start();//2.获取节点数据byte[] nodeDateBytes = client.getData().forPath("/app1");System.out.println("节点数据 = " + new String(nodeDateBytes));//3.关闭客户端,释放资源client.close();}
删除节点
    @Testpublic void deleteNode() throws Exception {//1.开启客户端client.start();//2.获取节点数据//方式1: 删除一个节点//client.delete().forPath("/app3");//方式2: 递归删除多个节点//client.delete().deletingChildrenIfNeeded().forPath("/app3");//方式3: 强制删除【避免一些因为网络传输导致的删除不成功】client.delete().guaranteed().forPath("/app3");//3.关闭客户端,释放资源client.close();}

ZK监听机制详解

watch机制如何运作?

watch机制本质就是订阅发布!采用了推拉结合的模式。

  • **推 **: 服务端感知到内容变化了,会发送事件信息给关注watch节点的客户端。事件本身是轻量的不含变更内容,这是“推”。
  • : 客户端收到变更通知事件,客户端需要自己去拉变更数据,这是“拉”。

Watch机制允许客户端在ZooKeeper上的数据节点发生变化时获得通知。它提供了一种事件驱动的编程模型,使得应用程序可以实时地监控和响应数据的变化,而无需持续地查询。

当客户端在某个数据节点上注册了一个Watch,它会在以下三种情况下被触发:

  • 数据节点的创建:当指定节点被创建时,与该节点相关联的Watch会被触发。
  • 数据节点的删除:当指定节点被删除时,与该节点相关联的Watch会被触发。
  • 数据节点的数据更新:当指定节点的数据发生变化时,与该节点相关联的Watch会被触发。

监听原理详解

Zookeeper观察者Watcher由三个部分组成,涉及消息通信及数据存储。

  • 客户端Client
  • 客户端监听管理器WatchManager
  • Zookeeper服务器Server

监听过程:

  1. Client向Server注册监听事件。
  2. Client将观察者Watcher存储到客户端的WatchManager里。
  3. Server触发对应事件之后,向Client推送(Push)消息通知。
  4. Client线程从WatchManager拿取回调Watcher执行业务逻辑,拉取节点数据(Pull)。

image.png
假如我们监听B节点,那么也可以监听B1、B2,但是孙子节点B11无法监听到。
image.png
注意:watcher设置后一旦触发一次后就会失效,如果要想一直监听,需要在process回调函数里重新注册相同的 watcher。

Apache Curator框架的监听实现:
Curator对watcher机制做了优化,Curator引入了Cache的概念用来实现对Zookeeper服务器端进行事件监听。Cache是Curator对事件监听的包装,其对事件的监听可以近似看做是一个本地缓存视图和远程Zookeeper视图的对比过程。而且Curator会自动的再次监听,我们就不需要自己手动的重复监听了。

**Curator客户端的Cache共有三种模式: **

  • 监听某节点的变化。
  • 监听某节点的子节点变化。
  • 监听整个树变化。

监听的三种模式

监听某节点的变化
public class Demo02Watch {CuratorFramework client;@Beforepublic void initClient() {//初始化Zookeeper的客户端对象clientString connectString = "127.0.0.1:2181";RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 100);int sessionTimeoutMs = 60 * 1000;//当前客户端会话超时时间int connectionTimeoutMs = 15 * 1000;//连接超时时间client =  CuratorFrameworkFactory.newClient(connectString, sessionTimeoutMs, connectionTimeoutMs, retryPolicy);}@Afterpublic void destroy(){client.close();}/*** 1.监听节点数据变化*/@Testpublic void listenNode() throws Exception {//1.启动客户端client.start();System.out.println("连接Zookeeper成功~~~~~~~~~~~~~~~~~~~");//2.创建节点监听对象NodeCache : 设置监听节点、监听回调方法NodeCache nodeCache = new NodeCache(client, "/hero");//设置监听节点ChildData currentData = nodeCache.getCurrentData();System.out.println("当前节点数据 = " + currentData);//开启监听nodeCache.start(true);//设置监听回调方法nodeCache.getListenable().addListener(new NodeCacheListener() {/*** 如果节点数据有变化,回调当前方法*/@Overridepublic void nodeChanged() throws Exception {//获取当前节点的数据ChildData currentData = nodeCache.getCurrentData();//获取最新节点名称String path = currentData.getPath();System.out.println("节点名称 = " + path);//获取最新节点数据byte[] currentDataByte = currentData.getData();System.out.println("修改后节点数据" + new String(currentDataByte));System.out.println("--------------->>");}});//从输入流中读取数据的下一个字节。//阻塞主线程//System.in.read();Thread.sleep(100000);}}
监听节点的子节点

PathChildrenCache是用来监听指定节点的子节点变化情况【新增、修改、删除】。
启动模式:

  1. NORMAL:这是默认的启动模式。在NORMAL模式下,PathChildrenCache会从指定的路径开始监听子节点的变化,并将子节点的当前状态缓存在本地。当有子节点增加、删除或更新时,PathChildrenCache会触发相应的事件通知,并更新本地缓存。
  2. BUILD_INITIAL_CACHE:在使用该模式启动PathChildrenCache之前,需要先调用rebuild()方法来构建初始的缓存。在BUILD_INITIAL_CACHE模式下,PathChildrenCache会首先从ZooKeeper服务器获取指定路径下的所有子节点,并将它们的状态缓存在本地。然后,PathChildrenCache开始监听子节点的变化,并在本地缓存的基础上进行更新。
  3. POST_INITIALIZED_EVENT:在使用该模式启动PathChildrenCache之前,需要先调用rebuild()方法来构建初始的缓存,类似于BUILD_INITIAL_CACHE模式。不同之处在于,使用POST_INITIALIZED_EVENT模式启动PathChildrenCache后,它会在完成初始缓存构建后,发送一个PathChildrenCacheEvent.Type.INITIALIZED类型的事件通知。

如何选用合适的模式?

  • 如果只关心子节点的当前状态,并希望在子节点变化时及时得到通知,可以使用NORMAL模式。
  • 如果需要在启动时获取所有子节点的初始状态,并维护一个本地缓存,可以选择BUILD_INITIAL_CACHE模式。
  • 如果需要在初始缓存构建完成后得到一个初始化完成的事件通知,可以选择POST_INITIALIZED_EVENT模式,其它方面跟BUILD_INITIAL_CACHE差不多。

触发回调的事件类型有哪些?

  1. Type.CONNECTION_RECONNECTED 重新连接
  2. Type.connection_lost 连接丢失
  3. Type.connection_suspended 连接暂停
  4. Type.INITIALIZED 初始化
  5. Type.CHILD_REMOVED 子节点移除
  6. Type.CHILD_ADDED 子节点添加
  7. Type.CHILD_UPDATED 子节点修改
/*** 2.监听当前节点的子节点变化,不含节点数据*/@Testpublic void listenSubNode2() throws Exception {//1.启动客户端client.start();System.out.println("连接Zookeeper成功~~~~~~~~~~~~~~~~~~~");//2.创建节点监听对象PathChildrenCache ://参数3,是否缓存数据PathChildrenCache childrenCache = new PathChildrenCache(client, "/hero", true);// 开启监听childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);// 设置监听回调方法childrenCache.getListenable().addListener((client, event) -> {//获取修改的数据byte[] bytes = event.getData().getData();System.out.println("节点内数据 = " + new String(bytes));//获取被修改的子节点System.out.println("节点名称 = " + event.getData().getPath());//获取事件类型//PathChildrenCacheEvent.Type.CONNECTION_RECONNECTED 重新连接//PathChildrenCacheEvent.Type.connection_lost 连接丢失//PathChildrenCacheEvent.Type.connection_suspended 连接暂停//PathChildrenCacheEvent.Type.INITIALIZED 初始化//PathChildrenCacheEvent.Type.CHILD_REMOVED 子节点移除//PathChildrenCacheEvent.Type.CHILD_ADDED 子节点添加//PathChildrenCacheEvent.Type.CHILD_UPDATED 子节点修改PathChildrenCacheEvent.Type type = event.getType();System.out.println("事件触发类型 = " + type);System.out.println("--------------------------------------------------->>");});//3.阻塞程序System.in.read();}
监听所有节点
/*** 3.树形监听所有下级节点变化【模式1+模式2】,含节点数据变更*/
@Test
public void treeCache() throws Exception {//1.启动客户端client.start();System.out.println("连接Zookeeper成功~~~~~~~~~~~~~~~~~~~");//2.创建节点监听对象TreeCache :TreeCache treeCache = new TreeCache(client, "/hero");//启动缓存treeCache.start();//添加监听回调方法treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {//获取修改的数据byte[] bytes = event.getData().getData();System.out.println("节点内数据 = " + new String(bytes));//获取被修改的子节点System.out.println("节点名称 = " + event.getData().getPath());//获取事件类型//TreeCacheEvent.Type.CONNECTION_RECONNECTED 重新连接//TreeCacheEvent.Type.connection_lost 连接丢失//TreeCacheEvent.Type.connection_suspended 连接暂停//TreeCacheEvent.Type.INITIALIZED 初始化//TreeCacheEvent.Type.NODE_REMOVED 子节点移除//TreeCacheEvent.Type.NODE_ADDED 子节点添加//TreeCacheEvent.Type.NODE_UPDATED 子节点修改TreeCacheEvent.Type type = event.getType();System.out.println("事件触发类型 = " + type);System.out.println("--------------------------------------------------->>");}});//3.阻塞程序System.in.read();
}

结尾

假如你认真读完本篇,那么你已经超越很多人了。

如果你对其感兴趣,可以看看下一篇,我们基于ZK手写一个简单的分布式锁,加强实践,巩固知识。https://blog.csdn.net/qq_38974073/article/details/135293504

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

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

相关文章

AI产品经理-借力

AI产品经理-借力&#xff1a;学会善用供应商改造自有产品 1.整个项目的工作方法 2.项目启动-行业调研 3.项目启动-供应商选型

喜讯|极狐GitLab 通过信通院汽车软件研发效能成熟度模型能力

12 月 27 日&#xff0c;在由中国信息通信研究院&#xff08;下称信通院&#xff09;、中国通信标准化协会联合主办的2023系统稳定性与精益软件工程大会-汽车云质效专场峰会上&#xff0c;信通院发布了“2023年下半年汽车云评估结果”&#xff0c;极狐GitLab 一体化 DevOps 平台…

centos7 使用openssl 配置证书服务器(史上最详细版本)

背景 最近接到一个任务&#xff1a;由于我们的产品涉及使用数字证书进行签名、签章&#xff0c;如果需要使得签名签章暗具有法律效力&#xff0c;就必须使用权威CA中心颁发的数字证书&#xff0c;就需要小钱钱&#xff1b;但是对于测试来说&#xff0c;就可以适当减少小钱钱的…

2023 年中国高校大数据挑战赛赛题B DNA 存储中的序列聚类与比对-解析与参考代码

题目背景&#xff1a;目前往往需要对测序后的序列进行聚类与比对。其中聚类指的是将测序序列聚类以判断原始序列有多少条&#xff0c;聚类后相同类的序列定义为一个簇。比对则是指在聚类基础上对一个簇内的序列进行比对进而输出一条最有 可能的正确序列。通过聚类与比对将会极大…

stata回归结果输出中,R方和F值到底是用来干嘛的?

先直接回答问题&#xff0c;R方表示可决系数&#xff0c;反映模型的拟合优度&#xff0c;也就是模型的解释能力如何&#xff0c;也可以理解为模型中的各个解释变量联合起来能够在多大程度上解释被解释变量&#xff1b;F值用于模型整体的统计显著性&#xff0c;对应的P值越小&am…

代码随想录刷题笔记(DAY2)

今日总结&#xff1a;今天在学 vue 做项目&#xff0c;学校还有很多作业要完成&#xff0c;熬到现在写完了三道题&#xff0c;有点太晚了&#xff0c;最后一道题的题解明天早起补上。&#xff08;补上了&#xff09; Day 2 01. 有序数组的平方&#xff08;No. 977&#xff09;…

力扣:968. 监控二叉树(贪心,二叉树)

题目&#xff1a; 给定一个二叉树&#xff0c;我们在树的节点上安装摄像头。 节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。 计算监控树的所有节点所需的最小摄像头数量。 示例 1&#xff1a; 输入&#xff1a;[0,0,null,0,0] 输出&#xff1a;1 解释&…

AIGC时代下,结合ChatGPT谈谈儿童教育

引言 都2024年了&#xff0c;谈到儿童教育&#xff0c;各位有什么新奇的想法嘛 我觉得第一要务&#xff0c;要注重习惯养成&#xff0c;我觉得聊习惯养成这件事情范围有点太大了&#xff0c;我想把习惯归纳于底层逻辑&#xff0c;我们大家都知道&#xff0c;在中国式教育下&a…

vue-cli3/webpack打包时去掉console.log调试信息

文章目录 前言一、terser-webpack-plugin是什么&#xff1f;二、使用配置vue-cli项目 前言 开发环境下&#xff0c;console.log调试信息&#xff0c;有助于我们找到错误&#xff0c;但在生产环境&#xff0c;不需要console.log打印调试信息&#xff0c;所以打包时需要将consol…

servlet+jdbc实现用户注册功能

一、需求 在Servlet中可以使用JDBC技术访问数据库&#xff0c;常见功能如下&#xff1a; 查询DB数据&#xff0c;然后生成显示页面&#xff0c;例如&#xff1a;列表显示功能。接收请求参数&#xff0c;然后对DB操作&#xff0c;例如&#xff1a;注册、登录、修改密码等功能。…

前端基本性能指标及lighthouse使用

文章目录 1、基本指标介绍2、Performace分析2.1 performance属性2.2 使用performace计算2.3 Resource Timing API2.4 不重复的耗时时段区分2.5 其他组合分析2.6 JS 总加载耗时2.7 CSS 总加载耗时 3、lighthouse基本使用3.1 使用Chrome插件lighthouse3.2 使用Chrome浏览器开发者…

信息泄露总结

文章目录 一、备份文件下载1.1 网站源码1.2 bak文件泄露1.3 vim缓存1.4 .DS_Store 二、Git泄露2.1 git知识点2.1 log2.2 stash 三、SVN泄露3.1 SVN简介3.2 SVN的文件3.3 SVN利用 四、Hg泄露 一、备份文件下载 1.1 网站源码 常见的网站源码备份文件后缀&#xff1a; tartar.gz…

hyperf console 执行

一、原理描述 hyperf中&#xff0c;不难发现比如自定义控制器中获取参数&#xff0c;hyperf.php中容器获取&#xff0c;传入的都是接口&#xff0c;而不是实体类。 这是因为框架中的配置文件有设置对应抽象类的子类&#xff0c;框架加载的时候将其作为数组&#xff0c;使用的…

零基础学Java第二天

复习回顾&#xff1a; 1.dos命令 dir 显示当前文件夹下面的所有的文件和文件夹 cd 切换目录的 mkdir 创建文件夹的 rd 删除文件夹的 del 删除文件 D: 切换盘符 cls 清屏 2.书写Java代码换行打印《静夜诗》这首古诗 class Demo1 { …

深入理解 C# 中的字符串比较:String.CompareTo vs String.Equals

深入理解 C# 中的字符串比较&#xff1a;String.CompareTo vs String.Equals 在处理字符串时&#xff0c;了解如何正确比较它们对于编写清晰、有效和可靠的 C# 程序至关重要。本文将深入探讨 C# 中的两个常用字符串比较方法&#xff1a;String.CompareTo 和 String.Equals&…

Mybatis行为配置之Ⅲ—其他行为配置项说明

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…

电子工程师如何接私活赚外快?

对电子工程师来说&#xff0c;利用业余时间接私活是个很常见的技术&#xff0c;不仅可以赚取额外收入&#xff0c;也能提升巩固技术&#xff0c;可以说国内十个工程师&#xff0c;必有五个在接私活养家糊口&#xff0c;如果第一次接私活&#xff0c;该如何做&#xff1f; 很多工…

再升级|川石教育鸿蒙应用开发4.0教程发布

全新鸿蒙蓄势待发 HarmonyOS是一款面向未来的全场景分布式智慧操作系统。 对于消费者而言&#xff0c;HarmonyOS用一个统一的软件系统从根本上解决消费者面对大量智能终端体验割裂的问题&#xff0c;为消费者带来统一、便利、安全的智慧化全场景体验。 对于开发者而言&#xf…

十二:爬虫-Scrapy框架(上)

一&#xff1a;Scrapy介绍 1.Scrapy是什么&#xff1f; Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架(异步爬虫框架) 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫&#xff0c;抓取指定网站的内容或图片 Scrapy使用了Twisted异步网…

(切图笔记)layui表格单元格添加超链接 以及传参方法 亲测可用 附代码

layui在切图网日常的工作中常常用到&#xff0c;特别是它的layer弹窗&#xff0c;基本可以满足网站切图时候遇到的绝大多数弹窗的情况&#xff0c;参数比较丰富 灵活&#xff0c;是不可多得的网页插件之一&#xff0c;我见很多人说layui过时了&#xff0c;这是相比于vue正流行的…