# 进入zookeeper1号容器中root@azang405:~# docker exec -it zk-1 /bin/bash# 进入到bin目录中root@f04635a2c8a3:/apache-zookeeper-3.7.0-bin# cd /apache-zookeeper-3.7.0-bin/bin
我们这里因为在之前笔记里面创建了一个单独的docker网络不了解docker网络的话可以去看一下我之前的博客docker网络
正因为我创建了独立的docker网络所以在下面的zookeeper命令中我是可以直接使用容器名加上端口号可以直接使用客户端连接对应的节点的
之所以说这些是因为上面我进入的容器是zk-1但是我下面连接的节点是zk-3,所以解释说明一下,
连接客户端zkCli.sh -server zk-3:2181
正文
# 在zk-1容器中连接root@f04635a2c8a3:/apache-zookeeper-3.7.0-bin/bin# zkCli.sh -server zk-3:2181Connecting to zk-3:21812022-02-10 10:57:02,271 [myid:] - INFO [main:Environment@98] - Client environment:zookeeper.version=3.7.0-e3704b390a6697bfdf4b0bef79e3da7a4f6bac4b, built on 2021-03-17 09:46 UTC2022-02-10 10:57:02,289 [myid:] - INFO [main:Environment@98] - Client environment:host.name=f04635a2c8a32022-02-10 10:57:02,289 [myid:] - INFO [main:Environment@98] - Client environment:java.version=11.0.132022-02-10 10:57:02,292 [myid:] - INFO [main:Environment@98] - Client environment:java.vendor=Oracle Corporation2022-02-10 10:57:02,292 [myid:] - INFO [main:Environment@98] - Client environment:java.home=/usr/local/openjdk-112022-02-10 10:57:02,293 [myid:] - INFO [main:Environment@98] - Client environment:java.class.path=/apache-zookeeper-3.7.0-bin/bin/../zookeeper-server/target/classes:/apache-zookeeper-3.7.0-bin/bin/../build/classes:/apache-zookeeper-3.7.0-bin/bin/../zookeeper-server/target/lib/*.jar:/apache-zookeeper-3.7.0-bin/bin/../build/lib/*.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/zookeeper-prometheus-metrics-3.7.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/zookeeper-jute-3.7.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/zookeeper-3.7.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/snappy-java-1.1.7.7.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/slf4j-log4j12-1.7.30.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/slf4j-api-1.7.30.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/simpleclient_servlet-0.9.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/simpleclient_hotspot-0.9.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/simpleclient_common-0.9.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/simpleclient-0.9.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-transport-native-unix-common-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-transport-native-epoll-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-transport-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-resolver-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-handler-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-common-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-codec-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/netty-buffer-4.1.59.Final.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/metrics-core-4.1.12.1.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/log4j-1.2.17.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jline-2.14.6.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-util-ajax-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-util-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-servlet-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-server-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-security-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-io-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jetty-http-9.4.38.v20210224.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/javax.servlet-api-3.1.0.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jackson-databind-2.10.5.1.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jackson-core-2.10.5.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/jackson-annotations-2.10.5.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/commons-cli-1.4.jar:/apache-zookeeper-3.7.0-bin/bin/../lib/audience-annotations-0.12.0.jar:/apache-zookeeper-3.7.0-bin/bin/../zookeeper-*.jar:/apache-zookeeper-3.7.0-bin/bin/../zookeeper-server/src/main/resources/lib/*.jar:/conf:2022-02-10 10:57:02,293 [myid:] - INFO [main:Environment@98] - Client environment:java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib2022-02-10 10:57:02,294 [myid:] - INFO [main:Environment@98] - Client environment:java.io.tmpdir=/tmp2022-02-10 10:57:02,294 [myid:] - INFO [main:Environment@98] - Client environment:java.compiler=
[zk: zk-3:2181(CONNECTED) 0] helpZooKeeper -server host:port -client-configuration properties-file cmd args addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE addauth scheme auth close config [-c] [-w] [-s] connect host:port # 普通创建节点 -s:含有序列 -e:临时(重启或者超时消失) create [-s] [-e] [-c] [-t ttl] path [data] [acl] # 删除一个节点 delete [-v version] path # 递归删除节点 deleteall path [-b batch size] delquota [-n|-b|-N|-B] path # 监听 get [-s] [-w] path getAcl [-s] path getAllChildrenNumber path getEphemerals path # 历史服务 history listquota path ls [-s] [-w] [-R] path printwatches on|off # 退出 quit reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*] redo cmdno removewatches path [-c|-d|-a] [-l] # 设置节点的具体值 set [-s] [-v version] path data setAcl [-s] [-v version] [-R] path acl setquota -n|-b|-N|-B val path # 查看节点状态 stat [-w] path sync path version whoami Command not found: Command not
查看 ls / : 查看当前znode(节点)中包含的内容ls -s / : 查看当前znode(节点)详细数据# 查看当前znode(节点)中包含的内容[zk: zk-3:2181(CONNECTED) 2] ls /[zookeeper]# 查看当前znode(节点)详细数据[zk: zk-3:2181(CONNECTED) 3] ls -s /# 参数解读[zookeeper]cZxid = 0x0# 创建节点的事务zxid: 每次修改ZooKeeper状态都会产生一个ZooKeeper事务ID.事务ID是ZooKeeper中所有修改的总次序.每次修改都有为一个zxid(事务ID),如果zxid1小于zxid2,那么zxid1在zxid2之前发生.ctime = Thu Jan 01 00:00:00 UTC 1970# znode被创建的毫秒数(从1970年开始)mZxid = 0x0# 当前znode最后更新的事务IDmtime = Thu Jan 01 00:00:00 UTC 1970# 当前znode最后修改的毫秒数(从1970年开始)pZxid = 0x0# 当前znode最后更新的子节点的事务ID(因为znode是树形结构的)cversion = -1# 当前znode子节点变化好,znode子节点修改次数dataVersion = 0# 当前znode数据变化的版本号aclVersion = 0# 当前znode访问控制列表的变化号ephemeralOwner = 0x0# 如果是临时节点,这个是当前znode拥有者的session_id.如果不是临时节点的话这永远是0.dataLength = 0# 当前znode的数据长度numChildren = 1# 当前znode子节点数量
(节点讲解)节点类型(持久/短暂/有序号/无序号) 持久(Persistent) : 客户端和服务器断开链接后,创建的节点不删除持久化目录节点(无序号): 例如znode1
客户端与ZooKeeper断开连接后,该节点依然存在
持久化顺序编号目录节点: 例如znode2_001
客户端与ZooKeeper断开连接后,该节点依旧存在,这只是ZooKeeper给该节点名称进行顺序编号
说明: 创建znode时设置顺序表示,znode名称后恢复加一个值,顺序号是一个单调递增的计数器,由父节点维护
注意: 在分布式中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序
短暂(Ephemeral) : 客户端和服务端断开链接后,创建的节点自己删除临时目录节点(无序号): 例如znode3
客户端与ZooKeeper断开连接后,该节点被删除
临时顺序编号目录节点: 例如znode4_001
客户端与ZooKeeper断开连接后,该节点被删除,只是ZooKeeper给该节点名称进行顺序编号
创建节点 create创建 持久化目录节点
create 节点名字 值
这里因为是非顺序编号目录节点,所以节点名是唯一的,不会去在后边有一个自增编号
# 创建一个值为null的持久化目录节点hao_da_er[zk: zk-3:2181(CONNECTED) 1] create /hao_da_erCreated /hao_da_er# 查看节点信息[zk: zk-3:2181(CONNECTED) 5] get -s /hao_da_er nullcZxid = 0x100000003ctime = Mon Feb 21 13:36:16 UTC 2022mZxid = 0x100000003mtime = Mon Feb 21 13:36:16 UTC 2022pZxid = 0x100000003cversion = 0dataVersion = 0aclVersion = 0ephemeralOwner = 0x0dataLength = 0numChildren = 0# 再次创建[zk: zk-3:2181(CONNECTED) 9] create /hao_da_er "heihei"# 这里可以看到显示hao_da_er节点已经存在无法创建了Node already exists: /hao_da_er
创建 持久化顺序编号目录节点
create -s 节点名字 值
当重复执行语句的时候节点名字会自增,这就是和非顺序编号目录节点的区别
# 创建持久化顺序编号目录节点[zk: zk-3:2181(CONNECTED) 6] create -s /hao_er_er "叫爸爸"# 这里我们可以看到创建的并不是我节点名字变成了 hao_er_er0000000001Created /hao_er_er0000000001# 查看节点信息[zk: zk-3:2181(CONNECTED) 7] get -s /hao_er_er0000000001 叫爸爸cZxid = 0x100000004ctime = Mon Feb 21 14:56:38 UTC 2022mZxid = 0x100000004mtime = Mon Feb 21 14:56:38 UTC 2022pZxid = 0x100000004cversion = 0dataVersion = 0aclVersion = 0ephemeralOwner = 0x0dataLength = 9numChildren = 0# 再次创建节点[zk: zk-3:2181(CONNECTED) 8] create -s /hao_er_er "叫爸爸"# 这里我们看到下方的节点编号进行了自增Created /hao_er_er0000000002
创建 临时目录节点
# 创建临时目录节点[zk: zk-3:2181(CONNECTED) 12] create -e /xiao_erziCreated /xiao_erzi# 查看[zk: zk-3:2181(CONNECTED) 13] get -s /xiao_erzinullcZxid = 0x10000000ectime = Wed Feb 23 14:41:10 UTC 2022mZxid = 0x10000000emtime = Wed Feb 23 14:41:10 UTC 2022pZxid = 0x10000000ecversion = 0dataVersion = 0aclVersion = 0ephemeralOwner = 0x30000fcab630003dataLength = 0numChildren = 0# 退出[zk: zk-3:2181(CONNECTED) 14] quit# 重连然后查看root@1d9718594b03:/apache-zookeeper-3.7.0-bin/bin# zkCli.sh -server zk-3:2181[zk: zk-3:2181(CONNECTED) 0] get -s /xiao_erzi# 节点无了org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = Nonode for /xiao_erzi
创建 临时顺序编号目录节点
# 创建临时顺序编号目录节点[zk: zk-3:2181(CONNECTED) 3] create -e -s /xiao_san_er "bobo"Created /xiao_san_er0000000003[zk: zk-3:2181(CONNECTED) 4] get -s/xiao_san_erorg.apache.commons.cli.UnrecognizedOptionException: Unrecognized option: -s/xiao_san_er[zk: zk-3:2181(CONNECTED) 5] get -s /xiao_san_erorg.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = Nonode for /xiao_san_er# 获取信息这里我没有断开连接我们可以看到下面产生了编号,同时也可以看到这里的编号是从3开始的说明顺序着上面的1和2[zk: zk-3:2181(CONNECTED) 6] get -s /xiao_san_er0000000003 bobocZxid = 0x100000008ctime = Wed Feb 23 14:00:40 UTC 2022mZxid = 0x100000008mtime = Wed Feb 23 14:00:40 UTC 2022pZxid = 0x100000008cversion = 0dataVersion = 0aclVersion = 0ephemeralOwner = 0x30000fcab630002dataLength = 4numChildren = 0# 这里我又创建了一个4号[zk: zk-3:2181(CONNECTED) 7] create -e -s /xiao_san_er "bobo"Created /xiao_san_er0000000004# 退出zk: zk-3:2181(CONNECTED) 8] quitWATCHER::WatchedEvent state:Closed type:None path:null2022-02-23 14:34:12,392 [myid:] - INFO [main:ZooKeeper@1232] - Session: 0x30000fcab630002 closed2022-02-23 14:34:12,392 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@570] - EventThread shut down for session: 0x30000fcab6300022022-02-23 14:34:12,396 [myid:] - ERROR [main:ServiceUtils@42] - Exiting JVM with code 0# 重新连接root@1d9718594b03:/apache-zookeeper-3.7.0-bin/bin# zkCli.sh -server zk-3:2181# 查询[zk: zk-3:2181(CONNECTED) 1] get -s /xiao_san_er0000000004# 这里看到异常没有节点了org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = Nonode for /xiao_san_er0000000004[zk: zk-3:2181(CONNECTED) 2] get -s /xiao_san_er0000000003org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = Nonode for /xiao_san_er0000000003# 再次执行创建[zk: zk-3:2181(CONNECTED) 7] create -e -s /xiao_san_er "bobo"# 这里发现编号已经变成5了,说明是继续增加的Created /xiao_san_er0000000005
监听器原理 监听原理详解 首先要有一个main()线程在main线程中创建ZooKeeper客户端,这是就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)通过connect线程将注册的监听事件发送给ZooKeeper、在ZooKeeper的注册监听器列表中将注册的监听事件添加到列表中listener线程内部调用了process()方法常见监听图解:
监听节点数据的变化
get path [watch]
监听子节点增减的变化
ls path [watch]
具体操作与探究节点的值变化监听
创建两次连接,我这里连接的都是同一个集群,然后我要监听的节点是hao_da_er这也是之前创建的节点
# 容器1root@1d9718594b03:/apache-zookeeper-3.7.0-bin# zkCli.sh -server zk-3:2181
# 容器2root@f04635a2c8a3:/apache-zookeeper-3.7.0-bin# zkCli.sh -server zk-3:2181
这里两条相同的命令,虽然命令式相同的但是可以从root后面可以看出来这是两个不同的容器但是连接的是一个zk集群,这里前言就是我是用docker运行的ZooKeeper容器
接下来我要在容器1中进行监听,在容器2中进行修改
# 容器1# 首先查看确认是否有hao_da_er节点[zk: zk-3:2181(CONNECTED) 2] ls -s /[hao_da_er, hao_er_er0000000001, hao_er_er0000000002, xiao_erer0000000006, zookeeper]cZxid = 0x0ctime = Thu Jan 01 00:00:00 UTC 1970mZxid = 0x0mtime = Thu Jan 01 00:00:00 UTC 1970pZxid = 0x10000000fcversion = 11dataVersion = 0aclVersion = 0ephemeralOwner = 0x0dataLength = 0numChildren = 5# 对hao_da_er节点进行监听[zk: zk-3:2181(CONNECTED) 3] get -w /hao_da_ernull
# 容器2# 直接对hao_da_er节点值进行修改[zk: zk-3:2181(CONNECTED) 1] set /hao_da_er "wobianle"
这时候回到容器1的shell界面我们可以实时看到
# 容器1# 这里就会监听到节点值被修改了[zk: zk-3:2181(CONNECTED) 4] WATCHER::WatchedEvent state:SyncConnected type:NodeDataChanged path:/hao_da_er
这里我们尝试容器1不重新注册监听然后容器2再一次修改节点值
# 容器2# 直接对hao_da_er节点值再次进行修改[zk: zk-3:2181(CONNECTED) 2] set /hao_da_er "wobianle"
这里我们会发现容器1的客户端没有任何的反应
注意⚠️:
注册一次,只能监听一次,想再次监听,需要再次注册.也就是说一次注册,当数据发生过一次改变也就是监听有效一次的时候那么这次注册也就消失了
节点的子节点变化监听(路径变化)
这里我们依旧使用容器1进行监听hao_da_er节点的子节点变化,同时依旧使用容器2来对hao_da_er节点的子节点进行修改
# 容器1# 监听hao_da_er节点[zk: zk-3:2181(CONNECTED) 4] ls -w /hao_da_er []
# 容器2# 创建子节点/hao_da_sun[zk: zk-3:2181(CONNECTED) 3] create /hao_da_er/hao_da_sunCreated /hao_da_er/hao_da_sun
我们回到容器一种可以看到
[zk: zk-3:2181(CONNECTED) 5] WATCHER::WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/hao_da_er
这里需要注意⚠️的是对于子节点变化的监听也是一次注册一次监听,无法多次监听
节点删除和查看 删除节点delete 节点
例子
# 首先查看一下所有节点[zk: zk-3:2181(CONNECTED) 5] ls -s /[hao_da_er, hao_er_er0000000001, hao_er_er0000000002, xiao_erer0000000006, zookeeper]cZxid = 0x0ctime = Thu Jan 01 00:00:00 UTC 1970mZxid = 0x0mtime = Thu Jan 01 00:00:00 UTC 1970pZxid = 0x10000000fcversion = 11dataVersion = 0aclVersion = 0ephemeralOwner = 0x0dataLength = 0numChildren = 5# 这里要删除节点/hao_er_er0000000001[zk: zk-3:2181(CONNECTED) 6] delete /hao_er_er0000000001# 再次查看发现已经删除成功了[zk: zk-3:2181(CONNECTED) 8] ls -s /[hao_da_er, hao_er_er0000000002, xiao_erer0000000006, zookeeper]cZxid = 0x0ctime = Thu Jan 01 00:00:00 UTC 1970mZxid = 0x0mtime = Thu Jan 01 00:00:00 UTC 1970pZxid = 0x100000016cversion = 12dataVersion = 0aclVersion = 0ephemeralOwner = 0x0dataLength = 0numChildren = 4
递归删除节点deleteall 节点
例子
# 首先查看节点[zk: zk-3:2181(CONNECTED) 14] ls -s /hao_da_er [hao_da_sun, hao_da_sun2] #两个子节点名(没有的话可以自己创建两个)cZxid = 0x100000003ctime = Mon Feb 21 13:36:16 UTC 2022mZxid = 0x100000014mtime = Thu Feb 24 14:53:56 UTC 2022pZxid = 0x100000017cversion = 2dataVersion = 2aclVersion = 0ephemeralOwner = 0x0dataLength = 11numChildren = 2 # 这里说明有两个子节点# 递归删除节点/hao_da_er/hao_da_sun2[zk: zk-3:2181(CONNECTED) 17] deleteall /hao_da_er/hao_da_sun2# 查看hao_da_er子节点[zk: zk-3:2181(CONNECTED) 18] ls -s /hao_da_er [hao_da_sun]cZxid = 0x100000003ctime = Mon Feb 21 13:36:16 UTC 2022mZxid = 0x100000014mtime = Thu Feb 24 14:53:56 UTC 2022pZxid = 0x100000018cversion = 3dataVersion = 2aclVersion = 0ephemeralOwner = 0x0dataLength = 11numChildren = 1# 接着递归删除节点/hao_da_er/hao_da_sun[zk: zk-3:2181(CONNECTED) 17] deleteall # 查看hao_da_er子节点[zk: zk-3:2181(CONNECTED) 19] deleteall /hao_da_er/hao_da_sun[zk: zk-3:2181(CONNECTED) 20] ls -s /hao_da_er []cZxid = 0x100000003ctime = Mon Feb 21 13:36:16 UTC 2022mZxid = 0x100000014mtime = Thu Feb 24 14:53:56 UTC 2022pZxid = 0x100000019cversion = 4dataVersion = 2aclVersion = 0ephemeralOwner = 0x0dataLength = 11numChildren = 0
查看节点状态stat 节点
例子
# 查看hao_da_er节点状态[zk: zk-3:2181(CONNECTED) 21] stat /hao_da_er cZxid = 0x100000003ctime = Mon Feb 21 13:36:16 UTC 2022mZxid = 0x100000014mtime = Thu Feb 24 14:53:56 UTC 2022pZxid = 0x100000019cversion = 4dataVersion = 2aclVersion = 0ephemeralOwner = 0x0dataLength = 11numChildren = 0