Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例
1. Zookeeper节点信息
指定服务端,启动客户端命令:
bin/zkCli.sh -server 服务端主机名:端口号
1)ls / 查看根节点下面的子节点
ls -s / 查看根节点下面的子节点以及根节点详细信息
其中,cZxid是创建节点的事务id,每次修改Zookeeper的状态都会产生一个事务id;
ctime是节点被创建的毫秒数(从1970年开始),这里是zookeeper自带的默认节点,其ctime就是0;mZxid是节点最后被更新的事务id;
mtime是节点最后修改的毫秒数;pZxid是最后更新的子节点的事务id;ephemeralOwner如果是临时节点则表示拥有这个节点的s
ession id,如果不是临时节点则为0;
dataLength是该节点的数据长度;
numChildren是该节点的子节点数量。
2. Zookeeper节点类型
持久节点:客户端和服务端断开连接后,创建的节点不删除
短暂/临时节点:客户端和服务端断开连接后,创建的节点删除
上面两种节点还可以继续分为带序号和不带序号的,如果带序号,节点名称后面会接一个数值,顺序递增,由父节点维护。
创建永久节点:create path "val"
(注意,ls命令后面的路径不能以/结尾,这里跟Linux不一样)
查询节点的值:get -s path
创建带序号的永久节点:create -s path "val"
以相同的路径再次创建同名节点,带序号的节点会自动序号加1,不带序号的节点创建报错
以上是永久节点,退出客户端之后这些节点依然存在
创建临时节点:create -e path "val"
创建带序号的临时节点只需加上-s即可
因为已经有shuguo,weiguo,wuguo,所以新创建的带序号的临时节点的序号为3。
断开客户端之后,上面创建的临时节点wuguo会被删除。
修改节点的值:set path "newVal"
3. 监听原理
监听主要是通过getChildren和getData来实现,表面上是获取节点子节点或者节点数据的方法,但是第二个参数表示是否监听,一般为true(第二个参数也可以传一个自定义的监听器),所以实现了监听,当子节点发生增减或者节点数据发生变化时,就会通知客户端,触发process方法。getChildren和getData是Java API监听方式,稍后介绍,这里先介绍命令行监听。
命令行开启监听节点数据:get -w path
在另一个会话端修改sanguo的节点值,在本端会产生事件通知:
再次在另一个会话端修改sanguo的节点值,在本端不会产生事件通知,因为监听只生效一次,要想再次监听,需要再次注册,即执行get -w path。
监控子节点变化:ls -w path
再另一个会话端创建一个子节点,在本端会产生一个事件通知
节点删除:delete path
删除节点及其下面的子节点:deleteall path
查看节点状态:stat path
4. Java API
添加pom依赖:
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.5.7</version>
</dependency>
建立Zookeeper连接:
Zookeeper zk = new Zookeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {}
})
其中connectString是主机地址,如果有多个主机,用逗号隔开,中间不能有空格。sessionTimeout是超时时间,单位是微秒。第三个参数是监听器,里面一般是根据事件类型以及事件路径来做相应的处理,也可在里面继续调用getChildren或者getData方法实现持续监听。
一旦连接上Zookeeper之后就会调用到process方法,里面一般会根据事件类型来对某个countDownLatch变量进行减1操作,在主线程中会等待这个变量为0,即等待Zookeeper连接上。
创建节点:
String node = zk.create(path, data, ZooDfs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
监控子节点的增删(注册监听):
List<String> children = zk.getChildren(path, true)for (String child : children) {System.out.println(child);
}
要想验证对子节点增删的监听,首先在java主线程中添加一个睡眠的函数,使其持续运行不至于很快结束,然后在process回调中添加相应的打印代码(比如继续getChildren,打印子节点信息),这样手动去添加节点,会执行到process函数中的打印信息。
判断节点是否存在:
Stat stat = ck.exists(path, false);
System.out.println(stat == null ? "not exist" : "exist");
5. 写数据原理
1)写请求直接发给Leader
其中,只要有半数节点写完,就可以发送ack给客户端,其他没写的服务端稍后再写。
2) 写请求发给Follower
这里也是半数节点写完就发送ack给客户端,所不同的是由接受写请求的Follower发送给客户端,而不是Leader,因为客户端最开始建立连接的是Follower。
6. 服务器动态上下线监听案例
分析:客户端监听服务器的上下线,本质是监听子节点的增删,服务器启动时会去Zookeeper集群注册(临时)子节点,使用的是create操作,而客户端监听则是get操作。注意这里的服务器和客户端对于Zookeeper集群来说都是客户端。
于是,代码主要分两部分,服务器创建子节点和客户端监听子节点。
// 服务器
private Zookeeper zk;public static void main(String[] args) throws Exception {// 创建本类(服务器类)的对象DistributeServer server = new DistributeServer();// 建立Zookeeper连接server.getConnect();// 注册,即创建子节点server.register(args[0]);// 服务端业务逻辑(睡觉)server.business();
}private void business() throws Exception {Thread.sleep(Long.MAX_VALUE);
}private void register(String hostName) throws Exception {String create = zk.create("/servers/" + hostName, hostName.getBytes(), ZooDef.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMRAL_SEQUENTIAL);System.out.println(hostName + "is online");
}private void getConnect() throws Exception {zk = new Zookeeper("xxx", 2000, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent){}});
}
// 客户端
private Zookeeper zk;public static void main(String[] args) throws Exception {// 创建本类(服务器类)的对象DistributeClient client = new DistributeClient();// 建立Zookeeper连接client.getConnect();// 注册,即创建子节点client.getServerList();// 客户端业务逻辑(睡觉)client.business();
}private void business() throws Exception {Thread.sleep(Long.MAX_VALUE);
}private void getServerList() throws Exception {List<String> children = zk.getChildren("/servers", true);List<String> servers = new ArrayList<>;for (String child : children) {byte[] data = zk.getData("/servers/" + child, false, null);servers.add(new String(data));}System.out.println(servers);
}private void getConnect() throws Exception {zk = new Zookeeper("xxx", 2000, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent){getServerList();}});
}
验证时,可以先验证客户端功能,服务端可以先用create -e -s 来代替,如果客户端功能ok,再继续验证服务端功能。
7. 分布式锁案例
分析:进程用客户端表示,每个客户端进程会去Zookeeper中创建一个临时带序号的子节点,如果子节点序号最小,则表示获取到锁,否则监听前一个序号更小的节点,持有锁执行完业务之后,会删除节点,表示释放锁,后面的节点/进场即可获取到锁。
private Zookeeper zk;
private String waitPath;
private String currentNode;
private CountDownLatch connectLatch = new CountDownLatch(1);
private CountDownLatch waitLatch = new CountDownLatch(1);public DistributeClient() throws Exception {// 创建本类(服务器类)的对象DistributeClient client = new DistributeClient();// 建立Zookeeper连接getConnect();connectLatch.await();
}// 加锁,创建临时节点,并判断是否是序号最小的节点,如果是则获取到锁,处理业务,如果不是,则监听前一个序号较小的节点
public void lock() throws Exception {// currentNode是全路径名String currentNode = zk.create("/locks/seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAGE, CreateMode.EPHEMETAL_SEQUENTIAL);List<String> children = zk.getChildren("locks", false);if (children.size() == 1) {return;} else {Collections.sort(children);String thisNode = currentNode.substring("/locks/".length());int index = children.indexOf(thisNode);if (index == -1) {System.out.println("数据异常");} else if (index == 0) {return;} else {// 监听前一个节点waitPath = "/locks/" + children.get(index -1);zk.getData(waitPath, true, null);waitLatch.await();}}}public void unlock() throws Exception {zk.delete(currentNode, -1);
}private void getConnect() throws Exception {zk = new Zookeeper("xxx", 2000, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {if (watchedEvent.getType() == Event.KeeperState.SyncConnected) {connectLatch.countDown(); }if (watchedEvent.getType() == Event.EventType.NodeDeleted && Event.getPath.equals(waitPath)) {waitLatch.countDown();}}});
}
测试步骤:建立两个线程,每个线程起一个客户端去加锁解锁(加日志打印),加锁解锁之间有睡眠,运行这两个线程,可以看到最终只有1个客户端去持有锁
8. Curator框架
上述分布式锁的案例中,有如下缺点:
1)会话印布链接,需要自己使用CountDownLatch处理
2)监听需要重复注册
3)代码较复杂
4)不支持多节点删除与创建
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.3.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.3.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>4.3.0</version>
</dependency>
public static void main(String[] args) {// 获取分布式锁1InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework, "/locks");// 获取分布式锁2InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework, "/locks");// 启动两个线程,分别加锁释放锁,该锁可重入// 加锁: lock1.acquire(); 释放锁: lock1.release();
}private static CuratorFramework getCuratorFramework() {ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString("xxx").connectionTimeoutMs(2000).sessionTimeoutMs(2000).retryPolicy(retry).build();client.start();System.out.println("客户端启动成功");return client;
}
9. 面试题

相关文章:

Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例
1. Zookeeper节点信息 指定服务端,启动客户端命令: bin/zkCli.sh -server 服务端主机名:端口号 1)ls / 查看根节点下面的子节点 ls -s / 查看根节点下面的子节点以及根节点详细信息 其中,cZxid是创建节点的事务id,…...

[嵌入式系统-34]:RT-Thread -19- 新手指南:RT-Thread标准版系统架构
目录 一、RT-Thread 简介 二、RT-Thread 概述 三、许可协议 四、RT-Thread 的架构 4.1 内核层: 4.2 组件与服务层: 4.3 RT-Thread 软件包: 一、RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然…...

postman访问k8s api
第一种方式: kubectl -n kubesphere-system get sa kubesphere -oyaml apiVersion: v1 kind: ServiceAccount metadata:annotations:meta.helm.sh/release-name: ks-coremeta.helm.sh/release-namespace: kubesphere-systemcreationTimestamp: "2023-07-24T07…...

UE4c++ ConvertActorsToStaticMesh
UE4c ConvertActorsToStaticMesh ConvertActorsToStaticMesh UE4c ConvertActorsToStaticMesh创建Edior模块(最好是放Editor模块毕竟是编辑器代码)创建UBlueprintFunctionLibraryUTestFunctionLibrary.hUTestFunctionLibrary.cpp:.Build.cs 目标:为了大量…...

Qt中tableView控件的使用
tableView使用注意事项 tableView在使用时,从工具栏拖动到底层页面后,右键进行选择如下图所示: 此处需要注意的是,需要去修改属性,从UI上修改属性如下所示: 也可以通过代码修改属性: //将其设…...

【医学影像】LIDC-IDRI数据集的无痛制作
LIDC-IDRI数据集制作 0.下载0.0 链接汇总0.1 步骤 1.合成CT图reference 0.下载 0.0 链接汇总 LIDC-IDRI官方网址:https://www.cancerimagingarchive.net/nbia-search/?CollectionCriteriaLIDC-IDRINBIA Data Retriever 下载链接:https://wiki.canceri…...
MacOS开发环境搭建详解
搭建MacOS开发环境需要准备相应的软硬件,并遵循一系列步骤。以下是详细的步骤: 软硬件准备: MacOS电脑:确保你的电脑运行的是MacOS操作系统。Xcode软件:打开AppStore,搜索并安装Xcode。安装过程可能较长&…...
全量知识系统问题及SmartChat给出的答复 之2
Q6. 根据DDD的思想( 也就是借助 DDD的某个或某些实现),是否能按照这个想法给出程序设计和代码结构? 当使用领域驱动设计(DDD)的思想来设计程序和代码结构时,可以根据领域模型、领域服务、值对象、实体等概念来进行设计…...
嵌入式驱动学习第一周——vim的使用
前言 本篇博客学习使用vim,vim作为linux下的编辑器,学linux肯定是绕不开vim的,因为不确定对方环境中是否安装了编译器,但一定会有vim。 对于基本的使用只需要会打开文件,保存文件,编辑文件即可。 嵌入式驱动…...
loop_list单向循环列表
#include "loop_list.h" //创建单向循环链表 loop_p create_head() { loop_p L(loop_p)malloc(sizeof(loop_list)); if(LNULL) { printf("create fail\n"); return NULL; } L->len 0; L->nextL; retur…...

Python爬虫实战第二例【二】
零.前言: 本文章借鉴:Python爬虫实战(五):根据关键字爬取某度图片批量下载到本地(附上完整源码)_python爬虫下载图片-CSDN博客 大佬的文章里面有API的获取,在这里我就不赘述了。 一…...

Eclipse是如何创建web project项目的?
前面几篇描述先后描述了tomcat的目录结构和访问机制,以及Eclipse的项目类型和怎么调用jar包,还有java的main函数等,这些是一些基础问题,基础高清出来才更容易搞清楚后面要说的东西,也就是需求带动学习,后面…...

Excel的中高级用法
单元格格式,根据数值的正负分配不同的颜色和↑ ↓ 根据数值正负分配颜色 2-7 [蓝色]#,##0;[红色]-#,##0 分配颜色的基础上,根据正负加↑和↓ 2↑-7↓ 其实就是在上面颜色的代码基础上加个 向上的符号↑,或向下的符号↓ [蓝色]#,##0↑;[红色…...

【ArcGIS】基本概念-空间参考与变换
ArcGIS基本概念-空间参考与变换 1 空间参考与地图投影1.1 空间参考1.2 大地坐标系(地理坐标系)1.3 投影坐标系总结 2 投影变换预处理2.1 定义投影2.2 转换自定义地理(坐标)变换2.3 转换坐标记法 3 投影变换3.1 矢量数据的投影变换…...

Qt QWidget 简约美观的加载动画 第五季 - 小方块风格
给大家分享两个小方块风格的加载动画 😊 第五季来啦 😊 效果如下: 一个三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QGridLayout> int main(int argc, char *arg…...

针对KZG承诺和高效laconic OT的extractable witness encryption
1. 引言 2024年以太坊基金会等成员论文 Extractable Witness Encryption for KZG Commitments and Efficient Laconic OT,开源代码实现见: https://github.com/rot256/research-we-kzg(Rust) 在该论文中,提供了一种…...

Spring Boot中实现列表数据导出为Excel文件
点击下载《Spring Boot中实现列表数据导出为Excel文件》 1. 前言 本文将详细介绍在Spring Boot框架中如何将列表数据导出为Excel文件。我们将通过Apache POI库来实现这一功能,并解释其背后的原理、提供完整的流程和步骤,以及带有详细注释的代码示例。最…...

华为ipv6 over ipv4 GRE隧道配置
思路: PC1访问PC2时,会先构造源ipv6为2001:1::2,目的IPV6为2001:2::2的ipv6报文,然后查看PC1的路由表,发送到R1,r1接收后,以目的IPV6地址2001:2::2查询IPV6路由表,出接口为tun0/0/0…...

项目解决方案:海外门店视频汇聚方案(全球性的连锁店、国外连锁店视频接入和汇聚方案)
目 录 一、概述 二、建设目标及需求 2.1 建设目标 2.2 需求描述 2.3 需求分析 三、建设方案设计 3.1 系统方案拓扑图 3.2 方案描述 3.3 服务器配置推荐 四、产品功能 4.1 资源管理平台 (1)用户权限管理 (2)…...
Java中的数据类型详解
引言 在Java编程中,数据类型是非常重要的概念,它定义了数据的类型和范围,帮助程序员有效地操作数据。Java的数据类型可以分为两大类:基本数据类型和引用数据类型。本文将详细介绍Java中的各种数据类型,并附上相应的代…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...