一起进阶学习JAVA:Zookeeper
- Zookeeper基本概念
- 集群角色
- 会话(Session)
- 数据节点(ZNode)
- 版本
- Watcher(事件监听器)
- ACL
- Zookeeper环境搭建
- 单机环境搭建
- 集群模式搭建
- Zookeeper基本使用
- Zookeeper系统模型
- Zookeeper数据模型ZNode
- ZNode的类型
- 事务ID
- ZNode的状态信息
- 数据变更通知---Watcher
- ACL---保障数据的安全
- 权限模式:Scheme
- 授权对象:ID
- 权限
- Zookeeper命令行操作
- Zookeeper的api使用
- Zookeeper开源客户端--zkClient
文章内容输出来源:拉勾教育Java高薪训练营
Zookeeper是一个开源的分布式协调服务,其设计目标是将复杂且容易出错的分布式一致性服务封装成一个高效可靠的原语集,并且以一些简单的接口提供给用户使用。Zookeeper是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于它实现注入数据订阅/发布于、负载均衡、命名服务、集群管理、分布式锁和分布式队列等服务。
Zookeeper基本概念
集群角色
通常在分布式系统中,构成一个集群的每一台机器都有自己的角色,最典型的就是Master/Slave的主备模式。能够处理写操作的机器成为Master机器,把所有通过异步复制方式获取最新数据,并提供服务的机器为Slave机器。
在Zookeeper中,它没有引用Master/Slave概念,而是引入Leader、Follower、Observer三种角色。Zookeeper集群中的所有机器通过Leader选举来选定一台呗成为Leader的机器,Leader服务器为客户端提供读和写的服务,除了Leader机器外的其他机器,包括Follower和Observer都能提供读服务,但是Observer机器不参与Leader选举过程,不参与写操作的过半写成功策略,因此Observer可以在不影响写性能的情况下提升集群的性能。
会话(Session)
Session指的是客户端会话,一个客户端连接是指客户端和服务端之间的一个TCP长连接,Zookeeper对外的服务端口默认为2181,客户端启动的时候,首先会与服务器建立一个TCP长连接,从第一次连接建立开始,客户端会话的生命周期也就开始了,通过这个连接,客户端能够使用心跳检测机制与服务器保持有效的会话,也能够向Zookeeper服务器发送请求并接受响应,同时还能通过该连接接受来自服务器的Watch事件通知。
数据节点(ZNode)
通常‘节点’指的是组成集群的每一台机器,然而在Zookeeper中,“节点”分为两类,第一类同样指的是组成集群的机器,我们称之为机器节点;第二类则指的是数据模型中数据单元,我们称之为数据节点–ZNode。在Zookeeper中会将所有的数据存储在内存中,数据模型是一棵树也成为ZNode Tree,又斜杠(/)进行分割的路径,就是一个ZNode,例如/znode/path1。每个ZNode上都会保存自己的数据内容以及一系列看ii的属性信息。
版本
对于每个ZNode,Zookeeper都会为其为维护一个叫做Stat的数据结构,Stat记录了这个ZNode的三个数据版本,分别是version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)、aversion(当前ZNode的ACL版本)。
Watcher(事件监听器)
Watcher事件监听器是在Zookeeper中很重要的特性,Zookeeper允许用户在指定节点上注册一些Watcher事件监听器,并且在特定时间触发的时候,Zookeeper服务端会将时间通知到感兴趣的客户端。
ACL
Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,其中定义了五种权限
- CREATE
创建子节点的权限 - READ
获取节点数据和子节点列表的权限 - WRITE
更新节点数据的权限 - DELETE
删除子节点的权限 - ADMIN
设置节点的ACL权限的权限
Zookeeper环境搭建
Zookeeper搭建均以Linux环境为例
单机环境搭建
-
下载安装包
首先下载稳定版本的zookeeper http://zookeeper.apache.org/releases.html,如下使用的版本为3.4.14》》zookeeper-3.4.14.tar.gz -
上传
将zookeeper安装压缩包zookeeper-3.4.14.tar.gz上传至服务器系统 -
解压缩安装包至/usr/local
cd /usr/local tar -zxvf zookeeper-3.4.14.tar.gz
-
创建data文件夹
cd zookeeper-3.4.14 mkdir data
-
修改配置文件名称
cd conf mv zoo_sample.cfg zoo.cfg
-
修改zoo.cfg中的data属性
dataDir=/usr/local/zookeeper-3.4.14/data
-
启动服务
./zkServer.sh start
输出以下内容表示启动成功
关闭服务输入命令
./zkServer.sh stop
输出以下提是信息表示关闭成功
查看状态输入命令
./zkServer.sh status
集群模式搭建
Zookeeper不但可以在单机上运行单机模式,而且可以在单机模拟集群模式。以下为单机情况下模拟集群模式的搭建。我们将不同的实例运行在一台机器,用端口区分。
我们在一台机器上部署了3个server,也就是说单台机器上运行多个Zookeeper实例,这种情况下我们要保证每个不同的zookeeper实例的端口号是不能冲突的,除了clientPort不同之外,dataDir也不同。另外,还要再dataDir所对应的目录中创建myid文件再指定对应的zookeeper服务器实例
- clientPort端口
如果在1台机器上部署多个zookeeper实例,那么每个实例需要不同的clientPort - dataDir和dataLogDir
如果在1台机器上部署多个zookeeper实例,dataDir和dataLogDir也需要区分 - server.X和myid
server.X这个数字就是对应data/myid中的数字。在3个server的myid文件中分别写入了1,2,3,那么每个server中的zoo.cfg都配置sever.1,server.2,server.3。在同一台机器上部署的情况下,后面连着的2个端接口都不能是一样的,否则会端口冲突
-
下载安装包
首先下载稳定版本的zookeeper http://zookeeper.apache.org/releases.html,如下使用的版本为3.4.14》》zookeeper-3.4.14.tar.gz -
上传
将zookeeper安装压缩包zookeeper-3.4.14.tar.gz上传至服务器系统 -
解压缩安装包至/usr/local中创建的新目录zkcluster中
cd /usr/local mkdir zkcluster tar -zxvf zookeeper-3.4.14.tar.gz -C /zkcluster
-
改变名称
mv zookeeper-3.4.14 zookeeper01
-
复制多分模拟多个实例并改名
cp -r zookeeper01/ zookeeper02 cp -r zookeeper01/ zookeeper03
-
分别在这三个实例文件夹中创建data及logs目录
cd /usr/local/zkcluster/zookeeper01 mkdir data cd data mkdir logs cd /usr/local/zkcluster/zookeeper02 mkdir data cd data mkdir logs cd /usr/local/zkcluster/zookeeper03 mkdir data cd data mkdir logs
-
修改配置文件名称(三个实例需要都修改)
cd /usr/local/zkcluster/zookeeper01/conf mv zoo_sample.cfg zoo.cfg
-
配置每一个Zookeeper的dataDir
clientPort=2181 dataDir=/usr/local/zkcluster/zookeeper01/data dataLogDir=/usr/local/zkcluster/zookeeper01/data/logs
clientPort=2182 dataDir=/usr/local/zkcluster/zookeeper02/data dataLogDir=/usr/local/zkcluster/zookeeper02/data/logs
clientPort=2183 dataDir=/usr/local/zkcluster/zookeeper03/data dataLogDir=/usr/local/zkcluster/zookeeper03/data/logs
-
配置集群
-
在每个Zookeeper的data目录下创建一个myid文件,内容分别是1,2,3。这个文件就是记录每个服务器的ID
touch myid
-
在每个zookeeper的zoo.cfg配置客户端访问端口和集群服务器IP列表
server.1=服务器IP:2881:3881 server.2=服务器IP:2882:3882 server.3=服务器IP:2883:3883 #server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间头皮选举端口
- 启动集群
依次启动三个zookeeper实例
Zookeeper基本使用
Zookeeper系统模型
Zookeeper数据模型ZNode
在Zookeeper中,数据信息被保存在一个个数据节点上,这些节点被称为ZNode。ZNode是zookeeper中的最小数据单位,在ZNode下面又可以再挂ZNode,一层层形成一个层次化命名空间的ZNode树,我们称之为ZNode Tree,它采取了类似文件系统的层级树状结构进行管理。
ZNode的类型
- 持久性节点(Persistent)
该节点被创建后会一直存在再服务器,直到删除操作主动清除 - 临时性节点(Ephemeral)
该节点的生命周期和客户端会话绑定在一起,客户端会话结束后节点就会被删除掉,临时性节点也不能创建子节点 - 顺序性节点(Sequential)
顺序性节点又分为持久顺序节点和临时顺修节点。这两种节点的特性和其对应的持久性和临时性的特性一样。不同的额外特性表现在顺序上,顺序特性实质就是在创建节点的时候,会在节点后面加上一个数字后缀来表示其顺序。
事务ID
在Zookeeper中,事务是指能够改变Zookeeper服务器状态的操作,我们也称之为事务操作或更新操作,一般包括数据节点的创建与删除、数据节点内容更新等操作。对于每一个事务请求,Zookeeper都会为其分配一个全局唯一的事务ID,用ZXID来表示,通常是一个64位的数字。每一个ZXID对于一次更新操作。
ZNode的状态信息
整个ZNode节点内容包括两个部分:
- 节点数据内容:上图quota是数据内容
- 节点状态信息:除quota意外全是状态信息
属性 | 全称 | 含义 |
---|---|---|
cZxid | Create ZXID | 节点被创建时的事务ID |
ctime | Create Time | 节点创建时间 |
mZxid | Modified ZXID | 节点最后一次被修改时的事务ID |
mtime | Modified Time | 节点最后一次被修改的时间 |
pZxid | / | 节点的子节点列表最后一次被修改时的事务ID。只有子节点列表变更才会更新,子节点内容变更时不会更新 |
cversion | / | 子节点版本号 |
dataVersion | / | 内容版本号 |
aclVersion | / | ACL版本 |
ephemeralOwner | / | 创建该临时节点时的花花sessionID,如果时持节性节点那么值为0 |
dataLength | / | 数据长度 |
numChildren | / | 直系子节点数 |
数据变更通知—Watcher
Zookeeper使用Watcher机制实现分布式数据的发布/订阅共嗯那个
Zookeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个时间通知来实现分布式的通知功能。
Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。
具体工作流程如下:
- 客户端在向Zookeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager当中
- 当Zookeeper服务器触发Watcher事件后,向客户端发送通知
- 客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑
ACL—保障数据的安全
Zookeeper作为一个分布式协调框架,其内部存储了分布式系统运行时状态的元数据,这些元数据会直接影响基于Zookeeper进行构造的分布式系统的运行状态,一次Zookeeper中提供了一套完善的ACL(Access Control List)权限控制机制来保障数据的安全。
权限模式:Scheme
权限模式用来确定权限验证过程中使用的检验策略
- IP
IP模式就是通过IP地址粒度来进行权限控制,如ip:192.168.0.110
表示针对192.168.0.110这个IP地址,同时也支持按网段方式进行配置,如ip:192.168.0.1/24
表示针对192.168.0.*这个网段进行权限控制。 - Digest
Digest是最常用的权限控制模式,它使用username:password
形式的权限标识来进行权限配置,便于区分不同应用来进行权限空直,当我们通过username:password
形式来妹纸之后,Zookeeper会先对其进行SHA-1加密和BASE64编码。 - World
World是一种最开放的权限控制模式,这种权限控制方式几乎没有任何作用,数据节点的访问权限是对全部用户进行开放的,同时World模式也是一种特殊的Digest模式,即world:anyone
- Super
超级用户模式,也是一种特殊的Digest模式,在Super模式下,超级用户可以对任意Zookeeper上的数据节点进行任何操作
授权对象:ID
授权对象是指权限赋予的用户或一个指定实体,例如IP地址或者机器等。
权限模式 | 授权对象 |
---|---|
IP | 通常是一个IP地址或地址段,如:192.168.0.110或192.168.0.1/24 |
Digest | 自定义,通常是username:BASE64(SHA-1(username:password)),例如:zm:sdfndsllndlksfn7c= |
World | 只有一个ID:anyone |
Super | 超级用户 |
权限
权限就是指哪些通过权限检查后被允许执行的操作,Zookeeper中又五大类权限
标识符 | 含义 | 描述 |
---|---|---|
C | CREATE | 数据节的创建权限,允许授权对象在该数据节点下创建子节点 |
D | DELETE | 子节点的删除权限,允许授权对象删除该数据节点的子节点 |
R | READ | 数据节点的读取权限,允许授权对象访问该节点并读取其数据内容和子节点列表等 |
W | WRITE | 数据节点的更新权限,允许授权对象访问该节点进行更新操作 |
A | ADMIN | 数据节点的管理权限,允许授权对象对该数据节点进行ACL相关的设置操作 |
Zookeeper命令行操作
- 使用zkClient进入zookeeper客户端命令行
cd /usr/local/zookeeper-3.4.14/bin
./zkcli.sh 连接本地的zookeeper服务器
./zkCli.sh -server ip:port 连接指定服务器
连接成功后,系统会输出Zookeeper的相关环境及配置信息。输入help后,屏幕会输出可用的zookeeper命令
-
创建节点
使用create命令create [-s][-e] path data acl #其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定则为持久节点; #acl用来进行权限控制 create -s /zk-test 123 #创建一个zk-test的顺序节点,节点内容为123 create -e /zk-temp 123 #创建一个zk-temp的临时节点,节点内容为123 create /zk-permanent 123 #创建一个zk-permanent的持节节点
退出使用quit
命令
-
读取节点
与读取相关的命令有ls
和get
命令
ls
命令可以列出Zookeeper指定节点下的所有子节点,但只能查看指定节点下的第一级的所有子节点ls path #其中,path标识的是指定数据节点的节点路径
get
命令可以获取Zookeeper指定节点的数据内容和属性信息get path
-
更新节点
-
使用
set
命令,可以更新指定节点的数据内容set path data [version]
其中,data就是要更新的新内容,version标识数据版本,在zookeeper中,节点数据是有版本概念的,这个参数用于指定本次操作时基于ZNode的哪一个数据版本进行的
set /zk-permanent 456 #将/zk-permanent数据更新为456
-
删除节点
使用delete
命令可以删除Zookeeper上的指定节点delete path [version]
其中version也是表示数据版本
delete /zk-permanent #删除/zk-permanent节点
若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点
Zookeeper的api使用
Zookeeper作为一个分布式框架,主要用于解决分布一致性问题,它提供了多种编程语言API,以下为java客户端的API使用方式
Zookeeper API共包含5个包:
org.apache.zookeeper
org.apache.zookeeper.data
org.apache.zookeeper.server
org.apache.zookeeper.server.quorum
org.apache.zookeeper.server.upgrade
其中org.apache.zookeeper
,包含Zookeeper类,是我们最常用的类文件。如果使用Zookeeper服务,必须先创建一个Zookeeper实例,一旦客户端和Zookeeper服务端建立起来连接,Zookeeper系统将会给本次会话分配一个ID指,并且客户端会周期性的向服务端发送心跳来维持会话连接。只要连接有效,客户端就可以使用Zookeeper API进行处理了。
- 准备工作:导入依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
- 建立会话
public class CreateSession implements Watcher {
//countDownLatch这个类使⼀个线程等待,主要不让main⽅法结束
private static CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws InterruptedException,
IOException {
ZooKeeper zooKeeper = new ZooKeeper("127.0.0.1:2181", 5000, new
CreateSession());
System.out.println(zooKeeper.getState());
countDownLatch.await();
//表示会话真正建⽴
System.out.println("=========Client Connected to zookeeper==========");
}
// 当前类实现了Watcher接⼝,重写了process⽅法,该⽅法负责处理来⾃Zookeeper服务端的watcher通知,在收到服务端发送过来的SyncConnected事件之后,解除主程序在CountDownLatch上的等待阻塞,⾄此,会话创建完毕
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
}
}
- 创建节点
public class CreateNote implements Watcher {
//countDownLatch这个类使⼀个线程等待,主要不让main⽅法结束
private static CountDownLatch countDownLatch = new CountDownLatch(1);
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws Exception {
zooKeeper = new ZooKeeper("127.0.0.1:2181", 5000, new CreateNote());
countDownLatch.await();
}
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
//调⽤创建节点⽅法
try {
createNodeSync();
} catch (Exception e) {
e.printStackTrace();
}
}
private void createNodeSync() throws Exception {
String node_PERSISTENT = zooKeeper.create("/lg_persistent", "持久节点内容".getBytes("utf-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
String node_PERSISTENT_SEQUENTIAL = zooKeeper.create("/lg_persistent_sequential", "持久节点内容".getBytes("utf-8"),ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
String node_EPERSISTENT = zooKeeper.create("/lg_ephemeral", "临时节点内容".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("创建的持久节点是:"+node_PERSISTENT);
System.out.println("创建的持久顺序节是:"+node_PERSISTENT_SEQUENTIAL);
System.out.println("创建的临时节点是:"+node_EPERSISTENT);
}
}
- 获取节点数据
public class GetNoteData implements Watcher {
//countDownLatch这个类使⼀个线程等待,主要不让main⽅法结束
private static CountDownLatch countDownLatch = new CountDownLatch(1);
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws Exception {
zooKeeper = new ZooKeeper("127.0.0.1:2181", 10000, new GetNoteDate());
Thread.sleep(Integer.MAX_VALUE);
}
public void process(WatchedEvent watchedEvent) {
//⼦节点列表发⽣变化时,服务器会发出NodeChildrenChanged通知,但不会把变化情况告诉给客户端
// 需要客户端⾃⾏获取,且通知是⼀次性的,需反复注册监听
if(watchedEvent.getType() ==Event.EventType.NodeChildrenChanged){
//再次获取节点数据
try {
List<String> children =
zooKeeper.getChildren(watchedEvent.getPath(), true);
System.out.println(children);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
try {
//调⽤获取单个节点数据⽅法
getNoteDate();
getChildrens();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void getNoteData() throws Exception {
byte[] data = zooKeeper.getData("/lg_persistent/lg-children", true,null);
System.out.println(new String(data,"utf-8"));
}
private static void getChildrens() throws KeeperException,InterruptedException {
List<String> children = zooKeeper.getChildren("/lg_persistent", true);
System.out.println(children);
}
}
- 修改节点
public class updateNote implements Watcher {
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws Exception {
zooKeeper = new ZooKeeper("127.0.0.1:2181", 5000, new updateNote());
Thread.sleep(Integer.MAX_VALUE);
}
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
try {
updateNodeSync();
} catch (Exception e) {
e.printStackTrace();
}
}
private void updateNodeSync() throws Exception {
byte[] data = zooKeeper.getData("/lg_persistent", false, null);
System.out.println("修改前的值:"+new String(data));
//修改 stat:状态信息对象 -1:最新版本
Stat stat = zooKeeper.setData("/lg_persistent", "客户端修改内容".getBytes(), -1);
byte[] data2 = zooKeeper.getData("/lg_persistent", false, null);
System.out.println("修改后的值:"+new String(data2));
}
}
- 删除节点数据
public class DeleteNote implements Watcher {
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws Exception {
zooKeeper = new ZooKeeper("10.211.55.4:2181", 5000, new DeleteNote());
Thread.sleep(Integer.MAX_VALUE);
}
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
try {
deleteNodeSync();
} catch (Exception e) {
e.printStackTrace();
}
}
private void deleteNodeSync() throws KeeperException,InterruptedException{
Stat exists = zooKeeper.exists("/lg_persistent/lg-children", false);
System.out.println(exists == null ? "该节点不存在":"该节点存在");
zooKeeper.delete("/lg_persistent/lg-children",-1);
Stat exists2 = zooKeeper.exists("/lg_persistent/lg-children", false);
System.out.println(exists2 == null ? "该节点不存在":"该节点存在");
}
}
Zookeeper开源客户端–zkClient
ZkClient是GitHub上的一个开源zookeeper客户端,再Zookeeper原生API接口上进行了包装,同时再内部还实现了Session超时重连、Watcher反复注册等功能
- 添加依赖
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>
- 创建会话
import java.io.IOException;
import org.I0Itec.zkclient.ZkClient;
public class CreateSession {
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
System.out.println("ZooKeeper session established.");
}
}
- 创建节点
import org.I0Itec.zkclient.ZkClient;
public class Create_Node_Sample {
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
System.out.println("ZooKeeper session established.");
//createParents的值设置为true,可以递归创建节点
zkClient.createPersistent("/lg-zkClient/lg-c1",true);
System.out.println("success create znode.");
}
}
- 删除节点
ZkClient提供了递归删除节点的接口,即帮助开发者先删除所有子节点(如果存在),再删除父节点
import org.I0Itec.zkclient.ZkClient;
public class Del_Data_Sample {
public static void main(String[] args) throws Exception {
String path = "/lg-zkClient/lg-c1";
ZkClient zkClient = new ZkClient("127.0.0.1:2181", 5000);
zkClient.deleteRecursive(path);
System.out.println("success delete znode.");
}
}
- 获取子节点
import java.util.List;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
public class Get_Children_Sample {
public static void main(String[] args) throws Exception {
ZkClient zkClient = new ZkClient("127.0.0.1:2181", 5000);
List<String> children = zkClient.getChildren("/lg-zkClient");
System.out.println(children);
//注册监听事件
zkClient.subscribeChildChanges(path, new IZkChildListener() {
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println(parentPath + " 's child changed,
currentChilds:" + currentChilds);
}
});
zkClient.createPersistent("/lg-zkClient");
Thread.sleep(1000);
zkClient.createPersistent("/lg-zkClient/c1");
Thread.sleep(1000);
zkClient.delete("/lg-zkClient/c1");
Thread.sleep(1000);
zkClient.delete(path);
Thread.sleep(Integer.MAX_VALUE);
}
}
- 获取数据(节点是否存在、更新、删除)
public class Get_Data_Sample {
public static void main(String[] args) throws InterruptedException {
String path = "/lg-zkClient-Ep";
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
//判断节点是否存在
boolean exists = zkClient.exists(path);
if (!exists){
zkClient.createEphemeral(path, "123");
}
//注册监听
zkClient.subscribeDataChanges(path, new IZkDataListener() {
public void handleDataChange(String path, Object data) throws Exception {
System.out.println(path+"该节点内容被更新,更新后的内容"+data);
}
public void handleDataDeleted(String s) throws Exception {
System.out.println(s+" 该节点被删除");
}
});
//获取节点内容
Object o = zkClient.readData(path);
System.out.println(o);
//更新
zkClient.writeData(path,"4567");
Thread.sleep(1000);
//删除
zkClient.delete(path);
Thread.sleep(1000);
}
}