Zookeeper学习笔记(持续更新中)

Zookeeper

1.Zookeeper是什么?

​ ZooKeeper 是一个开源的分布式应用程序协调服务框架,是 Google 的 Chubby 一个开源的实现,它提供了简单原始的功能,分布式应用可以基于它实现更高级的服务,比 如分布式同步,配置管理,集群管理,命名管理,队列管理。它被设计为易于编程,使用文件系统目录树作为数据模型。服务端跑在 java 上,提供 java 和 C 的客户端 API 。众所周知,协调服务非常容易出错,但是却很难恢复正常,例如,协调服务很容易处于竞态以至于出现死锁。我们设计 ZooKeeper 的目的为了减轻分布式应用程序所承担的协调任务。 ZooKeeper 是集群的管理者监视着集群中各节点的状态,根据节点提交的反馈进行下 一步合理的操作。最终,将简单易用的接口和功能稳定,性能高效的系统提供给用户。

​ 客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的 zookeeper 机器来处理。对于写请求,这些请求会同时发给其他 zookeeper 机器并且达成一致后,请求才会返回成功。因此,随着 zookeeper 的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。

1.1Zookeeper的时间/有序性

==有序性==是 zookeeper 中非常重要的一个特性,致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。也就是说,每个对节点的改变都将产生一个唯一的Zxid(Zookeeper Transaction Id)。如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个 zookeeper 最新的 zxid。 实际上,ZooKeeper的每个节点维护者三个Zxid值,为别为:cZxid、mZxid、pZxid。

cZxid: 是节点的创建时间所对应的Zxid格式时间戳。

② mZxid:是节点的修改时间所对应的Zxid格式时间戳。

③ pZxid: 是与 该节点的子节点(或该节点)的最近一次 创建 / 删除 的时间戳对应

实现中Zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个 新的epoch。低32位是个递增计数(2) 版本号

对节点的每一个操作都将致使这个节点的版本号增加。每个节点维护着三个版本号,他们分别为:

① version:节点数据版本号
② cversion:子节点版本号
③ aversion:节点所拥有的ACL版本号

1.2Zookeeper如何提供服务

​ ZooKeeper在实现比如分布式锁、配置维护、组服务等服务时,它首先设计了一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。

2. ZooKeeper组成

主要包括两部分文件系统通知机制

2.1文件系统

ZooKeeper维护一个类似Linux文件系统的数据结构,用于存储数据

  • 数据模型结构是一种树形结构,由许多节点构成
  • 每个节点叫做ZNode(ZooKeeper Node)
  • 每个节点对应一个唯一路径,通过该路径来标识节点,如 /app1/p_2
  • Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为 1M
2.1.1节点类型

​ » Znode有两种类型,短暂的(ephemeral)和持久的(persistent)
  » Znode的类型在创建时确定并且之后不能再修改
  » 短暂znode的客户端会话结束时,zookeeper会将该短暂znode删除,短暂znode不可以有子节点
  » 持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除

» Znode有四种形式的目录节点
  » PERSISTENT(持久的)
  » EPHEMERAL(暂时的)
  » PERSISTENT_SEQUENTIAL(持久化顺序编号目录节点)
  » EPHEMERAL_SEQUENTIAL(暂时化顺序编号目录节点)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HBJrM9Xz-1606313837254)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201105172108468.png)]

2.1.2ZooKeeper的数据模型特点

​ 从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:

(1) 引用方式

Znode通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串"/zookeeper"用以保存管理信息,比如关键配额信息。

(2) Znode结构

ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:

stat:此为状态信息, 描述该Znode的版本, 权限等信息

data:与该Znode关联的数据

children:该Znode下的子节点

ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但常规使用中应该远小于此值。

(3) 数据访问

ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

(4) 节点类型

ZooKeeper中的节点有两种,分别为临时节点永久节点。节点的类型在创建时即被确定,并且不能改变。

① 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点

② 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除

(5) 顺序节点

当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。

(6) 观察

客户端可以在节点上设置watch,我们称之为监视器。当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量

2.2通知机制——Watcher机制

ZooKeeper是一个基于观察者模式设计的分布式服务管理框架

  1. ZooKeeper负责管理和维护项目的公共数据,并授受观察者的注册(订阅)
  2. 一旦这些数据发生变化,ZooKeeper就会通知已注册的观察者
  3. 此时观察者就可以做出相应的反应

​ 简单来说, ZooKeeper是一个订阅中心(注册中心)。client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些 client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。

2.2.1Watcher机制的原理

​ ZooKeeper 的 Watcher 机制主要包括客户端线程、客户端 WatcherManager、Zookeeper 服务器三部分。客户端在向 ZooKeeper 服务器注册的同时,会将 Watcher 对象存储在客户端的 WatcherManager 当中。当 ZooKeeper 服务器触发 Watcher 事件后,会向客户端发送通知, 客户端线程从 WatcherManager 中取出对应的 Watcher 对象来执行回调逻辑。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktt7EA9B-1606313837255)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201105180204522.png)]

3.Zookeeper的角色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJA3FqRV-1606313837255)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201106084727764.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nKdG4Bl-1606313837256)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201106084755719.png)]

3.1Zookeeper的核心

​ • Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协
   议
Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者
   崩溃
后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后
   ,恢复模式就结束
了。状态同步保证了leader和Server具有相同的系统状态

3.2事务的顺序一致性

​ • 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(
   proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识
   leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的
   统治时期。低32位用于递增计数。

3.3 Server工作过程中的三种状态

• 每个Server在工作过程中有三种状态:
    LOOKING:当前Server不知道leader是谁,正在搜寻
    LEADING:当前Server即为选举出来的leader
    FOLLOWING:leader已经选举出来,当前Server与之同步

3.4Observer

​ • Zookeeper需保证高可用和强一致性;
  • 为了支持更多的客户端,需要增加更多Server;
  • Server增多,投票阶段延迟增大,影响性能;
  • 权衡伸缩性和高吞吐率,引入Observer

• Observer不参与投票;
  • Observers接受客户端的连接,并将写请求转发给leader节点;
  • 加入更多Observer节点,提高伸缩性,同时不影响吞吐率

4.Zookeeper的工作原理

» Zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式和广播模式。

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server的完成了和leader的状态同步以后,恢复模式就结束了。

状态同步保证了leader和server具有相同的系统状态

» 一旦leader已经和多数的follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个server加入zookeeper服务中,它会在恢复模式下启动,

发现leader,并和leader进行状态同步。待到同步结束,它也参与消息广播。Zookeeper服务一直维持在Broadcast状态,直到leader崩溃了或者leader失去了大部分的followers支持。

» 广播模式需要保证proposal被按顺序处理,因此zk采用了递增的事务id号(zxid)来保证。所有的提议(proposal)都在被提出的时候加上了zxid。

实现中zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位是个递增计数。

» 当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的server都恢复到一个正确的状态。

» 每个Server启动以后都询问其它的Server它要投票给谁。
  » 对于其他server的询问,server每次根据自己的状态都回复自己推荐的leader的id和上一次处理事务的zxid(系统启动时每个server都会推荐自己)
  » 收到所有Server回复以后,就计算出zxid最大的哪个Server,并将这个Server相关信息设置成下一次要投票的Server。
  » 计算这过程中获得票数最多的的sever为获胜者,如果获胜者的票数超过半数,则改server被选为leader。否则,继续这个过程,直到leader被选举出来

» leader就会开始等待server连接
  » Follower连接leader,将最大的zxid发送给leader
  » Leader根据follower的zxid确定同步点
  » 完成同步后通知follower 已经成为uptodate状态
  » Follower收到uptodate消息后,又可以重新接受client的请求进行服务了

5、Zookeeper节点数据操作流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1AFm2HJ-1606313837257)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201106090112293.png)]

​ 1.在Client向Follwer发出一个写的请求

2.Follwer把请求发送给Leader

3.Leader接收到以后开始发起投票并通知Follwer进行投票

4.Follwer把投票结果发送给Leader

5.Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;

6.Follwer把请求结果返回给Client

6、Zookeeper 的读写机制

» Zookeeper是一个由多个server组成的集群
  » 一个leader,多个follower
  » 每个server保存一份数据副本
  » 全局数据一致
  » 分布式读写
  » 更新请求转发,由leader实施

7、Zookeeper 的保证

» 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
  » 数据更新原子性,一次数据更新要么成功,要么失败
  » 全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的
  » 实时性,在一定事件范围内,client能读到最新数据

8.Zookeeper的数据一致性与paxos 算法

8.1数据一致性的原则

​ 在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态

8.2paxos 算法

​ Paxos算法解决的什么问题呢,解决的就是保证每个节点执行相同的操作序列。好吧,这还不简单,master维护一个全局写队列,所有写操作都必须放入这个队列编号,那么无论我们写多少个节点,只要写操作是按编号来的,就能保证一致性。没错,就是这样,可是如果master挂了呢。

Paxos算法通过投票写操作进行全局编号同一时刻只有一个写操作被批准,同时并发的写操作要去争取选票,只有获得过半数选票的写操作才会被批准(所以永远只会有一个写操作得到批准),其他的写操作竞争失败只好再发起一轮投票,就这样,在日复一日年复一年的投票中,所有写操作都被严格编号排 序编号严格递增,当一个节点接受了一个编号为100的写操作,之后又接受到编号为99的写操作(因为网络延迟等很多不可预见原因),它马上能意识到自己数据不一致了,自动停止对外服务并重启同步过程。任何一个节点挂掉都不会影响整个集群的数据一致性(总2n+1台,除非挂掉大于n台)

9.Zookeeper集群的数目为什么一般为奇数个?

•Leader选举算法采用了Paxos协议;
  •Paxos核心思想:当多数Server写成功,则任务数据写成功;如果有3个Server,则两个写成功即可;如果有4或5个Server,则三个写成功即可。
  •Server数目一般为奇数(3、5、7)如果有3个Server,则最多允许1个Server挂掉;如果有4个Server,则同样最多允许1个Server挂掉由此,

可以看出3台服务器和4台服务器的的容灾能力是一样的,所以为了节省服务器资源,一般我们采用奇数个数,作为服务器部署个数。

10.Zookeeper的常用命令

10.1查看

查看当前节点下的所有节点——ls /

查看当前节点下的节点——ls /节点名字

查看当前节点下的数据——get /节点名字

10.2创建节点

create [-s] [-e] 节点名字 节点数据

-s:secquence 有序节点

-e:ephemeral 临时节点

10.3修改节点数据

set 节点名称 节点数据

10.4删除节点数据

删除没有子节点的节点数据——delete 节点名称

删除当前节点及其所有子节点的节点数据——deleteall 节点名称

11.Zookeeeper集群

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pMsW7voV-1606313837258)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201106152856190.png)]

12.Zookeeper投票机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-StasPLSZ-1606313837259)(C:\Users\ThinkPad\AppData\Roaming\Typora\typora-user-images\image-20201106153303851.png)]

13.Java操作Zookeeper

13.1连接Zoookeeper
13.1.1创建Maven项目
13.1.2导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
    </parent>

    <groupId>com.qy.code</groupId>
    <artifactId>springboot-zookeeper</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        <maven.test.skip>true</maven.test.skip>
        <java.version>1.8</java.version>
        <spring.boot.version>2.0.1.RELEASE</spring.boot.version>
        <qy.code.version>0.0.1-SNAPSHOT</qy.code.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <!-- 不使用springboot默认log -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        

        <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.12</version>
            <!-- 排除冲突jar -->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>
        
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <version>2.3.5.RELEASE</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <repositories>
        <repository>
            <id>nexus-aliyun</id>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>nexus-aliyun</id>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


    <build>
        <plugins>
            <!-- 要将源码放上去,需要加入这个插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <configuration>
                    <attach>true</attach>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
13.1.3编写连接Zookeeper的工具类
package com.sonnie.springbootzookeeper02;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

/**
 * 连接Zookeeper集群
 * */
public class ZkUtil {
    public static CuratorFramework curatorFramework(){

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,2);

        CuratorFramework curatorFramework = CuratorFrameworkFactory
                .builder().connectString("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183")
                .retryPolicy(retryPolicy)
                .build();
        curatorFramework.start();
        return curatorFramework;
    }
}
13.1.4测试类
@Test
void Connect() {
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
}
13.2操作Zookeeper
13.2.1查询节点信息
/**
 * 查看节点
 * */
public static void selectZnode() throws Exception {
    //创建连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //查询
    List<String> znodeList = curatorFramework.getChildren().forPath("/");
    for (String s: znodeList
    ) {
        System.out.println(s);
    }
}

/**
 * 查看节点数据
 * */
public static void getZnodeData() throws Exception{
    //创建连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //查询
    byte[] bytes =  curatorFramework.getData().forPath("/zookeeper");
    System.out.println(bytes);
}
13.1.2添加节点
/**
 * 添加节点
 * */
public static void createZnode() throws Exception{
    //创建连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //添加
    curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath("/test01","test01".getBytes());
}
13.1.3修改节点数据
/**
 * 修改节点数据
 * */
public static void updateZnodeData() throws  Exception{
    //创建连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //修改
    curatorFramework.setData().forPath("/test01","01test".getBytes());
}
13.1.4查看znode状态
/**
 * 查看节点状态
 * */
public static void getZnodeStat() throws Exception{
    //创建连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //查看节点状态
    Stat stat = curatorFramework.checkExists().forPath("/test01");
    System.out.println(stat);
}
13.1.5删除节点
/**
 * 删除节点
 * */
public static void deleteZnode() throws Exception{
    //连接
    CuratorFramework curatorFramework = ZkUtil.curatorFramework();
    //删除
    curatorFramework.delete().deletingChildrenIfNeeded().forPath("/test01");
}
13.3监听通知机制
13.3.1.连接Zookeeper
13.3.2.创建NodeCache对象,指定要监听的znode
13.3.3.添加监听器
13.3.4利用System.in.read()避免程序停止

代码

   /**
     * 监听机制
     * */
    public static void listen() throws Exception {
//        创建连接
        CuratorFramework curatorFramework = ZkUtil.curatorFramework();
//        创建NodeCache对象,指定要监听的znode
        NodeCache nodeCache = new NodeCache(curatorFramework,"/test01");
        nodeCache.start();
//        添加监听器
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                String path =  nodeCache.getCurrentData().getPath();
                byte[] bytes = nodeCache.getCurrentData().getData();
                Stat stat =  nodeCache.getCurrentData().getStat();
                System.out.println("当前监听的节点为: " + path);
                System.out.println("当前监听的节点数据为: " + bytes);
                System.out.println("当前监听的节点的状态为: " + stat);
            }
        });
        System.out.println("开始监听!");
//        利用System.in.read()避免程序停止
        System.in.read();
    }

le().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
String path = nodeCache.getCurrentData().getPath();
byte[] bytes = nodeCache.getCurrentData().getData();
Stat stat = nodeCache.getCurrentData().getStat();
System.out.println("当前监听的节点为: " + path);
System.out.println("当前监听的节点数据为: " + bytes);
System.out.println("当前监听的节点的状态为: " + stat);
}
});
System.out.println(“开始监听!”);
// 利用System.in.read()避免程序停止
System.in.read();
}


















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SONNIE在路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值