ZooKeeper

ZooKeeper入门

  1. Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目
  2. 工作机制
    1. Zookeeper从设计模式角度来理解:是一个基于观察者设计的分布式管理框架,它负责存储和管理数据,然后接受观察者的注册,一旦这些数据的状态发生变化,zookeeper就负责通知已经注册观察者做出相应的反应
    2. Zookeeper=文件系统+通知机制
  3. 特点:
    在这里插入图片描述
    1. zookeeper:一个领导者(leader),多个跟随者(follower)组成的集群
    2. 集群中只要有半数以上的节点存活,zookeeper就能正常工作
    3. 全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server数据都是一致的
    4. 更新请求顺序进行:来自同一个client的更新请求按其发送的顺序依次执行
    5. 数据更新原子性,依次数据要么成功要么失败
    6. 在一定时间范围内,client能读到最新数据;
  4. 数据结构
    1. zookeeper跟unix文件系统很类似,整体上可以看成一棵树,每个节点成为ZNode,每个ZNode默认能够存储1M的数据,每个ZNode都可以通过其路径唯一标识;
      在这里插入图片描述
  5. 应用场景
    1. 提供的服务包括:统一命名服务,统一配置管理,统一集群管理,服务器节点动态上下线,软负载均衡;
    2. 统一命名服务:在分布式环境下,对应用或者服务统一进行命名,便于识别;
    3. 统一配置管理:
      1. 分布式环境下,配置文件同步非常常见
        1. 一般要求一个集群中,所有节点的配置信息时一致的比如Kafka集群
        2. 对配置文件修改后,希望能够快速同步到各个节点上
      2. 配置文件可以交给zookeeper来实现
        1. 可将配置文件写到zookeeper的一个znode;
        2. 各个客户端服务器监听这个znode;
        3. 一旦znode的数据被修改,zookeeper将通知各个客户端服务器;
      3. 统一集群管理
        1. 分布式环境中,实时掌握每个节点的状态是必要的
          1. 可根据节点实时状态做出一些调整
        2. zookeeper可以实现实时监控节点状态变化
          1. 可以将节点信息写入zookeeper上的znode
          2. 监听这个znode可以获取他的实时状态变化
      4. 服务器动态上下线:客户端能实时洞察到服务器上下线的变化
      5. 软负载均衡:在zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求

安装

  1. https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/或者apache官网https://zookeeper.apache.org/下载zookeeper的tar包;
  2. 安装jdk:下载解压tar包然后配置环境变量
    JAVA_HOME=/opt/jdk1.8.0_211
    PATH=$PATH:$JAVA_HOME/bin
    CLASSPATH=.:$JAVA_HOME/lib/
    export PATH JAVA_HOME CLASSPATH
    
  3. 将zookeeper的tar包解压到opt目录下,然后将zoo_sample.conf改成zoo.conf(方便修改),然后修改配置中dataDir=/opt/zookeeper-3.4.14/zkData(将数据存储到该目录下,目录需要单独创建)
  4. 启动zookeeper服务:bin/zkServer.sh start,使用jps可以查看服务是否启动,使用bin/zkServer.sh status可以查看服务状态;
    [root@localhost zookeeper-3.4.14]# jps
    18227 QuorumPeerMain
    19002 Jps
    root@localhost zookeeper-3.4.14]# bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /opt/zookeeper-3.4.14/bin/../conf/zoo.cfg
    Mode: standalone
    
  5. 启动客户端:bin/zkCli.sh即可
root@localhost zookeeper-3.4.14]# bin/zkCli.sh
Connecting to localhost:2181
2019-05-14 22:23:29,016 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
2019-05-14 22:23:29,024 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=localhost
2019-05-14 22:23:29,024 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.8.0_211
2019-05-14 22:23:29,026 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:java.home=/opt/jdk1.8.0_211/jre
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:java.class.path=/opt/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/opt/zookeeper-3.4.14/bin/../build/classes:/opt/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/opt/zookeeper-3.4.14/bin/../build/lib/*.jar:/opt/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/opt/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/opt/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/opt/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/opt/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/opt/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/opt/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/opt/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/opt/zookeeper-3.4.14/bin/../conf:.:/opt/jdk1.8.0_211/lib/
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:java.compiler=<NA>
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:os.name=Linux
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:os.arch=amd64
2019-05-14 22:23:29,027 [myid:] - INFO  [main:Environment@100] - Client environment:os.version=3.10.0-957.10.1.el7.x86_64
2019-05-14 22:23:29,028 [myid:] - INFO  [main:Environment@100] - Client environment:user.name=root
2019-05-14 22:23:29,028 [myid:] - INFO  [main:Environment@100] - Client environment:user.home=/root
2019-05-14 22:23:29,028 [myid:] - INFO  [main:Environment@100] - Client environment:user.dir=/opt/zookeeper-3.4.14
2019-05-14 22:23:29,029 [myid:] - INFO  [main:ZooKeeper@442] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@446cdf90
Welcome to ZooKeeper!
2019-05-14 22:23:29,063 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2019-05-14 22:23:29,179 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@879] - Socket connection established to localhost/127.0.0.1:2181, initiating session
2019-05-14 22:23:29,189 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x1000010aee70002, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] 
  1. 退出客户端:quit
[zk: localhost:2181(CONNECTED) 5] quit
Quitting...
2019-05-14 22:25:20,703 [myid:] - INFO  [main:ZooKeeper@693] - Session: 0x1000010aee70002 closed
2019-05-14 22:25:20,705 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@522] - EventThread shut down for session: 0x1000010aee70002
[root@localhost zookeeper-3.4.14]# 
  1. 退出服务端 :bin/zkServer.sh stop
[root@localhost zookeeper-3.4.14]# bin/zkServer.sh stop
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.14/bin/../conf/zoo.cfg
Stopping zookeeper ... STOPPED
[root@localhost zookeeper-3.4.14]# 
  1. 配置参数详解
    1. tickTime =2000:通信心跳数,Zookeeper服务器与客户端心跳时间,单位毫秒
      Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。
      它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)
    2. initLimit =10:LF初始通信时限
      集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。
    3. syncLimit =5:LF同步通信时限
      集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。
    4. dataDir:数据文件目录+数据持久化路径
      主要用于保存Zookeeper中的数据。
    5. clientPort =2181:客户端连接端口
      监听客户端连接的端口。

内部原理

选举机制

  1. 半数机制:集群中半数以上机器存活,集群可用。所以zookeeper适合安装奇数台服务器(5台服务器挂3台集群不可用,6台服务器挂3台也不可用,因为没有半数以上存活,所以依旧不可用,因此第六台作用没那么大,建议奇数台服务器);
  2. Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的(超过半数以上)。假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么
    在这里插入图片描述
    1. 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。
    2. 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
    3. 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
    4. 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
    5. 服务器5启动,同4一样当小弟。

节点类型

  1. 持久:客户端与服务端断开连接之后,创建的节点不删除
    1. 持久化目录节点:客户端与zookeeper断开连接之后,该节点依旧存在
    2. 持久化顺序编号目录节点:客户端与zookeeper断开连接之后,该节点依旧存在,知识zookeeper给该节点名称进行顺序编号。好处是:顺序号可以用于被所有事件进行全局排序,这样客户端可以通过顺序号推断时间的顺序;
  2. 短暂:客户端和服务器断开连接之后,创建的节点自己删除
    1. 临时目录节点:客户端zookeeper断开连接之后,该节点被删除(例如服务器动态上下线)
    2. 临时顺序编号目录节点:客户端与zookeeper断开连接之后,该节点被删除,只是zookeeper为该节点名称进行顺序编号;

stat 结构体

[zk: localhost:2181(CONNECTED) 39] get /huzd
huzd
cZxid = 0x27
ctime = Wed May 15 22:02:33 CST 2019
mZxid = 0x27
mtime = Wed May 15 22:02:33 CST 2019
pZxid = 0x27
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
  1. cZxid:创建节点的事务id,每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生;
  2. ctime:被创建的时间
  3. mZxid:最后修改的事务zxid
  4. mtime:最后修改的时间
  5. pZxid:最后更新的子节点zxid
  6. cversion:子节点变化号,znode子节点修改的次数
  7. dataversion:数据变化号
  8. aclVesion:访问控制列表变化号
  9. ephemeralOwner:临时节点的拥有者的sessionid,如果不是临时节点,则为0
  10. dataLength:节点的数据长度
  11. numChildren:子节点数目

监听器的原理

原理详解

在这里插入图片描述

  1. 首先有一个main线程
  2. 在main线程里面创建zookeeper客户端,这时会创建两个线程,一个负责连接,一个负责监听
  3. 通过连接线程将注册的监听事件发送给zookeeper,包括客户端自身ip跟listener监听端口(订阅)
  4. zookeeper将注册的监听事件添加的注册监听器列表中
  5. zookeeper监听该事件是否发送变化,一旦发生变化通过之前注册的客户端ip跟listener端口将变化通知给客户端;
  6. 客户端监听器线程调用process方法处理变化;

常见的监听

  1. 监听节点数据的变化:get path watch
  2. 监听子节点增减的变化:ls path watch

写数据流程

在这里插入图片描述

  1. 客户端向zookeeper的server1上面发起一个写数据请求
  2. server1接受到请求,如果server1不是leader,则将请求转发给leader,leader在将请求广播给各个server(follower),各个server将写请求执行成功之后会返回通知leader
  3. 当leader收到一半以上的写成功之后就认为写成功了,然后通知最开始的server1写请求成功
  4. server1进一步通知客户端写请求成功;

实战

客户端命令行操作

命令行基本语法功能描述
help显示所有操作命令
ls path [watch]使用ls命令来查看当前znode中所包含的内容
ls2 path [watch]查看当前节点数据并能看到详细信息
create普通创建 -s:含有序列 -e:临时(重启或者超时消失)
get path [watch]获得节点的值
set设置节点的具体值
stat查看节点状态
delete删除节点
rmr递归删除节点
  1. help:显示所有操作命令
[zk: localhost:2181(CONNECTED) 11] help
ZooKeeper -server host:port cmd args
	stat path [watch]
	set path data [version]
	ls path [watch]
	delquota [-n|-b] path
	ls2 path [watch]
	setAcl path acl
	setquota -n|-b val path
	history 
	redo cmdno
	printwatches on|off
	delete path [version]
	sync path
	listquota path
	rmr path
	get path [watch]
	create [-s] [-e] path data acl
	addauth scheme auth
	quit 
	getAcl path
	close 
	connect host:port
[zk: localhost:2181(CONNECTED) 12]
  1. ls:显示路径下内容,跟linux略微不同的是,末尾不能有/
[zk: localhost:2181(CONNECTED) 12] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 13] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 14] ls /zookeeper/quota/
Command failed: java.lang.IllegalArgumentException: Path must not end with / character
[zk: localhost:2181(CONNECTED) 15] 

  1. ls2:显示路径下内容详细信息
[zk: localhost:2181(CONNECTED) 15] ls2 /zookeeper
[quota]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
[zk: localhost:2181(CONNECTED) 16] 
  1. create:创建节点
[zk: localhost:2181(CONNECTED) 16] create /huzd "huzd"

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/
Created /huzd
[zk: localhost:2181(CONNECTED) 17] ls /
[zookeeper, huzd]
[zk: localhost:2181(CONNECTED) 18]
  1. get:获取节点值
[zk: localhost:2181(CONNECTED) 2] get /huzd      
huzd
cZxid = 0x8
ctime = Wed May 15 20:53:21 CST 2019
mZxid = 0x8
mtime = Wed May 15 20:53:21 CST 2019
pZxid = 0x8
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 3] 
  1. 创建短暂节点(Ephemeral):create -e /huzd/test test
[zk: localhost:2181(CONNECTED) 15] create -e /huzd/test test
Created /huzd/test
[zk: localhost:2181(CONNECTED) 20] ls /huzd
[test]
[zk: localhost:2181(CONNECTED) 21] quit
重新连接
[zk: localhost:2181(CONNECTED) 0] ls /huzd
[]
[zk: localhost:2181(CONNECTED) 1] 
  1. 创建带有序号的节点
[zk: localhost:2181(CONNECTED) 0] create -s /huzd/test test
Created /huzd/test0000000003
[zk: localhost:2181(CONNECTED) 1] create -s /huzd/test test
Created /huzd/test0000000004
[zk: localhost:2181(CONNECTED) 2] create -s /huzd/test test
Created /huzd/test0000000005
[zk: localhost:2181(CONNECTED) 3] 
  1. 修改节点数据 set
[zk: localhost:2181(CONNECTED) 14] create /huzd huzd
Created /huzd
[zk: localhost:2181(CONNECTED) 15] get /huzd
huzd
cZxid = 0x1e
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x1e
mtime = Wed May 15 21:40:27 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 16] set /huzd test
cZxid = 0x1e
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x1f
mtime = Wed May 15 21:40:52 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 17] get /huzd
test
cZxid = 0x1e
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x1f
mtime = Wed May 15 21:40:52 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 18] 
  1. 查看节点状态
[zk: localhost:2181(CONNECTED) 18] stat /huzd
cZxid = 0x1e
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x1f
mtime = Wed May 15 21:40:52 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 19] 
  1. 在get或者set命令后面加上watch可以表示监听该节点变化,一旦有变化,会有通知(但是只有一次有效,通知完之后如果需要继续监听需要在watch)
[zk: localhost:2181(CONNECTED) 20] get /huzd watch
test
cZxid = 0x1e
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x1f
mtime = Wed May 15 21:40:52 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 21] set /huzd huzd
cZxid = 0x1e
注意下面这里!!
WATCHER::


WatchedEvent state:SyncConnected type:NodeDataChanged path:/huzd
ctime = Wed May 15 21:40:27 CST 2019
mZxid = 0x20
mtime = Wed May 15 21:48:11 CST 2019
pZxid = 0x1e
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 22] 
  1. 删除节点
[zk: localhost:2181(CONNECTED) 27] ls /huzd
[huzd]
[zk: localhost:2181(CONNECTED) 28] ls /huzd/huzd
[]
[zk: localhost:2181(CONNECTED) 29] delete /huzd
Node not empty: /huzd
[zk: localhost:2181(CONNECTED) 30] delete /huzd/huzd
[zk: localhost:2181(CONNECTED) 31] ls /huzd
[]
[zk: localhost:2181(CONNECTED) 32] create /huzd/huzd huzd
Created /huzd/huzd
[zk: localhost:2181(CONNECTED) 33] ls /huzd
[huzd]
[zk: localhost:2181(CONNECTED) 34] rmr /huzd 
[zk: localhost:2181(CONNECTED) 35] 

API应用

  1. 创建Maven工程
  2. 引入zookeeper的依赖,同时还需要junit(我这边放到父pom文件中)跟log4j-core;

parent.pom

<dependencyManagement>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/junit/junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
	</dependencies>
</dependencyManagement>

ZookeeperTest.pom

  <parent>
	  <groupId>com.huzd.study</groupId>
	  <artifactId>Parent</artifactId>
	  <version>0.0.1-SNAPSHOT</version>
	  <relativePath>../Parent/pom.xml</relativePath>
  </parent>
  
  <dependencies>
  	<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
	<dependency>
	    <groupId>org.apache.zookeeper</groupId>
	    <artifactId>zookeeper</artifactId>
	    <version>3.4.14</version>
	</dependency>

	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-core</artifactId>
		<version>2.11.1</version>
	</dependency>
	
	
  </dependencies>
  1. 关闭虚拟机防火墙或者设置允许的端口
    关于centos7的防火墙命令
    1. 启动防火墙:systemctl start firewalld
    2. 查看防火墙状态:systemctl status firewalld 或者 firewall-cmd --state
    3. 显示防火墙public区域允许的端口号:firewall-cmd --zone=public --list-ports
    4. 增加端口到指定区域:firewall-cmd --zone=public --add-port=2181/tcp
    5. 删除端口:firewall-cmd --zone= public --remove-port=80/tcp --permanent
    6. 重启服务:firewall-cmd --reload
    7. 停止防火墙:systemctl disable firewalld
    8. 禁用防火墙:systemctl stop firewalld
  2. 在Maven工程的src/main/resources路径下配置log4j.properties
log4j.rootLogger=INFO,CON
#CON
log4j.appender.CON=org.apache.log4j.ConsoleAppender
log4j.appender.CON.layout=org.apache.log4j.PatternLayout
log4j.appender.CON.layout.ConversionPattern=threadId[%X{thId}] logId[%X{bizId}] FunctionId[%X{FunctionId}] %d %p[%C:%L]- %m%n

  1. 使用api连接
public class TestZk {

	private String connectString = "192.168.175.128:2181";
	private int sessionTimeout = 2000;
	private ZooKeeper zooKeeper = null;
	private CountDownLatch countDownLatch = new CountDownLatch(1);
	
	@Before
	public void init() throws IOException, InterruptedException {
		zooKeeper  = new ZooKeeper(connectString, sessionTimeout , new Watcher() {
			
			@Override
			public void process(WatchedEvent event) {
				if (event.getState() == KeeperState.SyncConnected) {
					System.out.println("连接成功");
					countDownLatch.countDown();
				}
			}
		});
		if(ZooKeeper.States.CONNECTING.equals(zooKeeper.getState())) {
			System.out.println("连接中");
			countDownLatch.await();
		}
	}
	
	@Test
	public void createNode() {
		try {
			String create = zooKeeper.create("/huzd", "huzd".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			System.out.println(create);
				
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	@Test
	public void getDataAndWatch() {
		
		try {
			List<String> children = zooKeeper.getChildren("/", false);
			for (String child : children) {
				System.out.println(child);
			}
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
}
  1. 需要注意的是由于Zookeeper是异步连接,因此如果调用了连接立刻用create方法会报错org.apache.zookeeper.KeeperException$ConnectionLossException,这是因为连接还没有连接上就调用了create,解决办法是配合watch跟CountDownLatch,主方法调用create之前判断zookeeper对象的状态是否是连接中,是的话就调用countDownLatch.await(),让主线程处于等待状态,在连接成功之后watch的even状态会返回KeeperState.SyncConnected,这时候调用countDownLatch.countDown(),通知主线程继续执行,这里也就是执行create;
  2. 创建节点成功
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,637 INFO[org.apache.zookeeper.Environment:100]- Client environment:zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,641 INFO[org.apache.zookeeper.Environment:100]- Client environment:host.name=home-huzd
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,641 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.version=1.8.0_151
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,641 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.vendor=Oracle Corporation
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,641 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.home=H:\software\jdk1.8\jre
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,641 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.class.path=H:\software\newEclipseWork\ZookeeperTest\target\test-classes;H:\software\newEclipseWork\ZookeeperTest\target\classes;H:\software\apache-maven-3.6.1\repository\org\apache\zookeeper\zookeeper\3.4.14\zookeeper-3.4.14.jar;H:\software\apache-maven-3.6.1\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;H:\software\apache-maven-3.6.1\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;H:\software\apache-maven-3.6.1\repository\com\github\spotbugs\spotbugs-annotations\3.1.9\spotbugs-annotations-3.1.9.jar;H:\software\apache-maven-3.6.1\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;H:\software\apache-maven-3.6.1\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;H:\software\apache-maven-3.6.1\repository\jline\jline\0.9.94\jline-0.9.94.jar;H:\software\apache-maven-3.6.1\repository\org\apache\yetus\audience-annotations\0.5.0\audience-annotations-0.5.0.jar;H:\software\apache-maven-3.6.1\repository\io\netty\netty\3.10.6.Final\netty-3.10.6.Final.jar;H:\software\apache-maven-3.6.1\repository\junit\junit\4.12\junit-4.12.jar;H:\software\apache-maven-3.6.1\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;H:\software\apache-maven-3.6.1\repository\org\apache\logging\log4j\log4j-core\2.11.1\log4j-core-2.11.1.jar;H:\software\apache-maven-3.6.1\repository\org\apache\logging\log4j\log4j-api\2.11.1\log4j-api-2.11.1.jar;H:\software\eclipse\configuration\org.eclipse.osgi\250\0\.cp;H:\software\eclipse\configuration\org.eclipse.osgi\249\0\.cp
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,642 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.library.path=H:\software\jdk1.8\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;H:/software/jdk1.8/bin/../jre/bin/server;H:/software/jdk1.8/bin/../jre/bin;H:/software/jdk1.8/bin/../jre/lib/amd64;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\IDM Computer Solutions\UltraEdit;C:\Users\lenovo\AppData\Local\Microsoft\WindowsApps;H:\software\jdk1.8\bin;H:\software\jdk1.8\jre\bin;H:\software\work\apache-tomcat-6.0.44-windows-x64\apache-tomcat-6.0.44\bin;H:\software\work\apache-tomcat-6.0.44-windows-x64\apache-tomcat-6.0.44\lib;H:\software\apache-maven-3.6.1\bin;C:\Users\lenovo\AppData\Local\Microsoft\WindowsApps;;H:\software\eclipse;;.
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,642 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.io.tmpdir=C:\Users\lenovo\AppData\Local\Temp\
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,642 INFO[org.apache.zookeeper.Environment:100]- Client environment:java.compiler=<NA>
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,642 INFO[org.apache.zookeeper.Environment:100]- Client environment:os.name=Windows 10
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,642 INFO[org.apache.zookeeper.Environment:100]- Client environment:os.arch=amd64
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,643 INFO[org.apache.zookeeper.Environment:100]- Client environment:os.version=10.0
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,643 INFO[org.apache.zookeeper.Environment:100]- Client environment:user.name=lenovo
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,643 INFO[org.apache.zookeeper.Environment:100]- Client environment:user.home=C:\Users\lenovo
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,643 INFO[org.apache.zookeeper.Environment:100]- Client environment:user.dir=H:\software\newEclipseWork\ZookeeperTest
threadId[] logId[] FunctionId[] 2019-05-17 22:05:41,645 INFO[org.apache.zookeeper.ZooKeeper:442]- Initiating client connection, connectString=192.168.175.128:2181 sessionTimeout=2000 watcher=com.huzd.study.TestZk$1@3d04a311
连接中
threadId[] logId[] FunctionId[] 2019-05-17 22:06:00,114 INFO[org.apache.zookeeper.ClientCnxn$SendThread:1025]- Opening socket connection to server 192.168.175.128/192.168.175.128:2181. Will not attempt to authenticate using SASL (unknown error)
threadId[] logId[] FunctionId[] 2019-05-17 22:06:00,116 INFO[org.apache.zookeeper.ClientCnxn$SendThread:879]- Socket connection established to 192.168.175.128/192.168.175.128:2181, initiating session
threadId[] logId[] FunctionId[] 2019-05-17 22:06:00,123 INFO[org.apache.zookeeper.ClientCnxn$SendThread:1299]- Session establishment complete on server 192.168.175.128/192.168.175.128:2181, sessionid = 0x100003429990009, negotiated timeout = 4000
连接成功
/huzd
  1. 获取节点并监控数据变化
	@Before
	public void init() throws IOException, InterruptedException {
		zooKeeper  = new ZooKeeper(connectString, sessionTimeout , new Watcher() {
			
			@Override
			public void process(WatchedEvent event) {
				if (event.getState() == KeeperState.SyncConnected) {
					System.out.println("连接成功");
					countDownLatch.countDown();
				}
				//监控必须在watch中才能生效,首先使用zooKeeper.getChildren方法,然后监控设置为true
				//然后执行getDataAndWatch方法,这里会一直阻塞主线程,让主线程不停止,然后当zookeeper的/根路径有节点变化时,会回调process方法打印变化
				try {
					List<String> children = zooKeeper.getChildren("/", true);
					for (String child : children) {
						System.out.println(child);
					}
				} catch (KeeperException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		if(ZooKeeper.States.CONNECTING.equals(zooKeeper.getState())) {
			System.out.println("连接中");
			countDownLatch.await();
		}
	}
	@Test
	public void getDataAndWatch() {
		
		try {
			Thread.sleep(Long.MAX_VALUE);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值