ZooKeeper命令⾏操作

⾸先,进⼊到zookeeper的bin⽬录之后,通过zkClient进⼊zookeeper客户端命令⾏

1
2
./zkcli.sh 连接本地的zookeeper服务器
./zkCli.sh -server ip:port(2181) 连接指定的服务器

连接成功之后,系统会输出Zookeeper的相关环境及配置信息等信息。输⼊help之后,屏幕会输出可⽤的Zookeeper命令,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[zk: localhost:2181(CONNECTED) 3] 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

创建节点

使⽤create命令,可以创建⼀个Zookeeper节点, 如

1
create [-s][-e] path data

其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定,则创建持久节点

创建顺序节点

使⽤命令创建zk-test顺序节点

1
2
[zk: localhost:2181(CONNECTED) 4] create -s /zk-test 123
Created /zk-test0000000000

执⾏完后,就在根节点下创建了⼀个叫做/zk-test的节点,该节点内容就是123,同时可以看到创建的zk-test节点后⾯添加了⼀串数字以示区别

创建临时节点

使⽤命令创建zk-temp临时节

1
2
3
4
[zk: localhost:2181(CONNECTED) 1] create -e /zk-temp 123
Created /zk-temp
[zk: localhost:2181(CONNECTED) 2] ls /
[zk-test0000000000, zookeeper, zk-temp]

临时节点在客户端会话结束后,就会⾃动删除,下⾯使⽤quit命令退出客户端

1
2
[zk: localhost:2181(CONNECTED) 3] quit
Quitting...

再次使⽤客户端连接服务端,并使⽤ls / 命令查看根⽬录下的节点

1
2
[zk: localhost:2181(CONNECTED) 0] ls /
[zk-test0000000000, zookeeper]

可以看到根⽬录下已经不存在zk-temp临时节点了

创建永久节点

使⽤命令创建zk-permanent永久节点 ,可以看到永久节点不同于顺序节点,不会⾃动在后⾯添加⼀串数字

1
2
3
4
[zk: localhost:2181(CONNECTED) 1] create /zk-permanent 123
Created /zk-permanent
[zk: localhost:2181(CONNECTED) 2] ls /
[zk-permanent, zk-test0000000000, zookeeper]

读取节点

与读取相关的命令有 ls 命令和 get 命令,其中,path表示的是指定数据节点的节点路径

ls 命令可以列出Zookeeper指定节点下的所有⼦节点,但只能查看指定节点下的第⼀级的所有⼦节点: ls path

get 命令可以获取Zookeeper指定节点的数据内容和属性信息: get path

若获取根节点下⾯的所有⼦节点,使⽤ls / 命令即可

1
2
[zk: localhost:2181(CONNECTED) 2] ls /
[zk-permanent, zk-test0000000000, zookeeper]

若想获取/zk-permanent的数据内容和属性,可使⽤如下命令:get /zk-permanent

1
2
3
4
5
6
7
8
9
10
11
12
13
[zk: localhost:2181(CONNECTED) 3] get /zk-permanent
123
cZxid = 0x300000008
ctime = Thu Jul 16 04:33:41 EDT 2020
mZxid = 0x300000008
mtime = Thu Jul 16 04:33:41 EDT 2020
pZxid = 0x300000008
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

从上⾯的输出信息中,我们可以看到,第⼀⾏是节点/zk-permanent 的数据内容,其他⼏⾏则是创建该节点的事务ID(cZxid)、最后⼀次更新该节点的事务ID(mZxid)和最后⼀次更新该节点的时间(mtime)等属性信息

更新节点

使⽤set命令,可以更新指定节点的数据内容,⽤法如下

1
set path data

其中,data就是要更新的新内容,version表示数据版本,在zookeeper中,节点的数据是有版本概念的,这个参数⽤于指定本次更新操作是基于Znode的哪⼀个数据版本进⾏的,如可以使⽤如下命令,将/zk-permanent节点的数据更新为456

1
2
3
4
5
6
7
8
9
10
11
12
[zk: localhost:2181(CONNECTED) 4] set /zk-permanent 456
cZxid = 0x300000008
ctime = Thu Jul 16 04:33:41 EDT 2020
mZxid = 0x300000009
mtime = Thu Jul 16 05:07:00 EDT 2020
pZxid = 0x300000008
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

现在dataVersion已经变为1了,表示进⾏了更新

删除节点

使⽤delete命令可以删除Zookeeper上的指定节点,⽤法如下

1
delete path

其中version也是表示数据版本,使⽤delete /zk-permanent 命令即可删除/zk-permanent节点

1
2
3
[zk: localhost:2181(CONNECTED) 8] delete /zk-permanent
[zk: localhost:2181(CONNECTED) 9] ls /
[zk-test0000000000, zookeeper]

可以看到,已经成功删除/zk-permanent节点。值得注意的是,若删除节点存在⼦节点,那么⽆法删除该节点,必须先删除⼦节点,再删除⽗节点

Zookeeper的Java开源客户端

ZkClient是Github上⼀个开源的zookeeper客户端,在Zookeeper原⽣API接⼝之上进⾏了包装,是⼀个更易⽤的Zookeeper客户端,同时,zkClient在内部还实现了诸如Session超时重连、Watcher反复注册等功能

接下来,还是从创建会话、创建节点、读取数据、更新数据、删除节点等⽅⾯来介绍如何使⽤zkClient这个zookeeper客户端

创建maven工程

  1. 添加依赖

在pom.xml⽂件中添加如下内容

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>
</dependencies>
  1. 创建会话

使⽤ZkClient可以轻松的创建会话,连接到服务端。

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.hust.grid.leesf.zkclient.examples;

import org.I0Itec.zkclient.ZkClient;

public class CreateSession {
/*
创建⼀个zkClient实例来进⾏连接
*/
public static void main(String[] args) {
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
System.out.println("ZooKeeper session created.");
}
}

运⾏结果:ZooKeeper session created.

结果表明已经成功创建会话。

创建节点

ZkClient提供了递归创建节点的接⼝,即其帮助开发者先完成⽗节点的创建,再创建⼦节点

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.hust.grid.leesf.zkclient.examples;

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.");
}
}

运⾏结果:success create znode.

结果表明已经成功创建了节点,值得注意的是,ZkClient通过设置createParents参数为true可以递归的先创建⽗节点,再创建⼦节点

删除节点

ZkClient提供了递归删除节点的接⼝,即其帮助开发者先删除所有⼦节点(存在),再删除⽗节点。

1
2
3
4
5
6
7
8
9
10
11
12
package com.hust.grid.leesf.zkclient.examples;

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.");
}
}

运⾏结果: success delete znode.

结果表明ZkClient可直接删除带⼦节点的⽗节点,因为其底层先删除其所有⼦节点,然后再删除⽗节点

监听节点变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.hust.grid.leesf.zkclient.examples;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.client.ZooKeeperSaslClient;
import java.util.List;

/*
* 演示zkClient如何使⽤监听器
* 1 监听器可以对不存在的⽬录进⾏监听
* 2 监听⽬录下⼦节点发⽣改变,可以接收到通知,携带数据有⼦节点列表
* 3 监听⽬录创建和删除本身也会被监听到
*/
public class Get_Child_Change {
public static void main(String[] args) throws InterruptedException {
//获取到zkClient
final ZkClient zkClient = new ZkClient("linux121:2181");
//zkClient对指定⽬录进⾏监听(不存在⽬录:/lg-client),指定收到通知之后的逻辑
//对/lag-client注册了监听器,监听器是⼀直监听
zkClient.subscribeChildChanges("/lg-client", new IZkChildListener() {
//该⽅法是接收到通知之后的执⾏逻辑定义
public void handleChildChange(String path, List<String> childs)
throws Exception {
//打印节点信息
System.out.println(path + " childs changes ,current childs " +
childs);
}
});

//使⽤zkClient创建节点,删除节点,验证监听器是否运⾏
zkClient.createPersistent("/lg-client");
Thread.sleep(1000); //只是为了⽅便观察结果数据
zkClient.createPersistent("/lg-client/c1");
Thread.sleep(1000);
zkClient.delete("/lg-client/c1");
Thread.sleep(1000);
zkClient.delete("/lg-client");
Thread.sleep(Integer.MAX_VALUE);
}
}

运⾏结果:

1
2
3
4
/lg-zkClient 's child changed, currentChilds:[]
/lg-zkClient 's child changed, currentChilds:[c1]
/lg-zkClient 's child changed, currentChilds:[]
/lg-zkClient 's child changed, currentChilds:null

结果表明:

  • 客户端可以对⼀个不存在的节点进⾏⼦节点变更的监听。

  • ⼀旦客户端对⼀个节点注册了⼦节点列表变更监听之后,那么当该节点的⼦节点列表发⽣变更时,服务端都会通知客户端,并将最新的⼦节点列表发送给客户端

  • 该节点本身的创建或删除也会通知到客户端。

监听节点数据变化(节点是否存在、更新、删除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.lagou.zk.demo;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

//使⽤监听器监听节点数据的变化
public class Get_Data_Change {
public static void main(String[] args) throws InterruptedException {
// 获取zkClient对象
final ZkClient zkClient = new ZkClient("Linux121:2181");
//设置⾃定义的序列化类型,否则会报错!!
zkClient.setZkSerializer(new ZkStrSerializer());
//判断节点是否存在,不存在创建节点并赋值
final boolean exists = zkClient.exists("/lg-client1");
if (!exists) {
zkClient.createEphemeral("/lg-client1", "123");
}
//注册监听器,节点数据改变的类型,接收通知后的处理逻辑定义
zkClient.subscribeDataChanges("/lg-client1", new IZkDataListener() {
public void handleDataChange(String path, Object data) throws
Exception {
//定义接收通知之后的处理逻辑
System.out.println(path + " data is changed ,new data " +
data);
}
//数据删除--》节点删除
public void handleDataDeleted(String path) throws Exception {
System.out.println(path + " is deleted!!");
}
});
//更新节点的数据,删除节点,验证监听器是否正常运⾏
final Object o = zkClient.readData("/lg-client1");
System.out.println(o);
zkClient.writeData("/lg-client1", "new data");
Thread.sleep(1000);
//删除节点
zkClient.delete("/lg-client1");
Thread.sleep(Integer.MAX_VALUE);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.lagou.zk.demo;

import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;

public class ZkStrSerializer implements ZkSerializer {
//序列化,数据--》byte[]
public byte[] serialize(Object o) throws ZkMarshallingError {
return String.valueOf(o).getBytes();
}
//反序列化,byte[]--->数据
public Object deserialize(byte[] bytes) throws ZkMarshallingError {
return new String(bytes);
}
}

运⾏结果:

1
2
3
123
/lg-client1 data is changed ,new data new data
/lg-client1 is deleted!!

结果表明可以成功监听节点数据变化或删除事件。