zookeeper客户端api操作

这里记录zookeeper java客户端api的使用。

客户端创建Zookeeper实例,然后调用这个类提供的方法与zookeeper服务器进行交互。
Zookeeper的构造函数有如下4种:

1
2
3
4
ZooKeeper(connectString, sessionTimeout, watcher);
ZooKeeper(connectString, sessionTimeout, watcher,canBeReadOnly);
ZooKeeper(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);
ZooKeeper(connectString, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly);

参数说明:
connectString: 连接字符串 例如 “127.0.0.1:2181”
sessionTimeout: 会话超时时间 以毫秒为单位的整型值 在sessionTimeout时间内服务端与客户端没有有效的心跳检测 则会话失效
watcher: 默认的事件通知处理器
sessionId: 会话ID
sessionPasswd: 会话秘钥
canBeReadOnly: 是否是只读

String create(String path, byte[] data, List acl,CreateMode createMode)
创建一个给定的目录节点 path, 并给它设置数据,CreateMode 标识有四种形式的目录节点,分别是 PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失;PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名;EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除;EPHEMERAL_SEQUENTIAL:临时自动编号节点

Stat exists(String path, boolean watch)
判断某个 path 是否存在,并设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper 实例时指定的 watcher,exists方法还有一个重载方法,可以指定特定的watcher

Stat exists(String path,Watcher watcher)
重载方法,这里给某个目录节点设置特定的 watcher,Watcher 在 ZooKeeper 是一个核心功能,Watcher 可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的 Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应

void delete(String path, int version)
删除 path 对应的目录节点,version 为 -1 可以匹配任何版本,也就删除了这个目录节点所有数据

ListgetChildren(String path, boolean watch)
获取指定 path 下的所有子目录节点,同样 getChildren方法也有一个重载方法可以设置特定的 watcher 监控子节点的状态

Stat setData(String path, byte[] data, int version)
给 path 设置数据,可以指定这个数据的版本号,如果 version 为 -1 怎可以匹配任何版本

byte[] getData(String path, boolean watch, Stat stat)
获取这个 path 对应的目录节点存储的数据,数据的版本等信息可以通过 stat 来指定,同时还可以设置是否监控这个目录节点数据的状态

void addAuthInfo(String scheme, byte[] auth)
客户端将自己的授权信息提交给服务器,服务器将根据这个授权信息验证客户端的访问权限。

Stat setACL(String path,List acl, int version)
给某个目录节点重新设置访问权限,需要注意的是 Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL由两部分组成:perms 和 id。Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种,而 id 标识了访问目录节点的身份列表,默认情况下有以下两种:ANYONE_ID_UNSAFE = new Id(“world”, “anyone”) 和 AUTH_IDS = new Id(“auth”, “”) 分别表示任何人都可以访问和创建者拥有访问权限。

List getACL(String path,Stat stat)
获取某个目录节点的访问权限列表

下面通过一个配置JDBC的url、username、password,并从zookeeper读取的示例来说明
配置类:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Created by j.tommy on 2017/9/8.
*/
public class ZkTest1 {
private final static String ZK_CONNECTION_STR = "192.168.74.125:2181";
private final static int SESSION_TIMEOUT = 30000;
private final static String AUTH_TYPE = "digest";
private final static String AUTH_ID_PWD = "admin:123456";
private final static String ZK_ROOT = "/dbConf";
private final static String ZK_URL = ZK_ROOT + "/url";
private final static String ZK_USERNAME = ZK_ROOT + "/username";
private final static String ZK_PWD = ZK_ROOT + "/password";
private ZooKeeper zk = null;
public ZkTest1() {
getZK();
}
public ZooKeeper getZK() {
try {
zk = new ZooKeeper(ZK_CONNECTION_STR, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent);
}
});
while (zk.getState() != ZooKeeper.States.CONNECTED) {
Thread.sleep(1000L);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return zk;
}
private void createNode(String path,byte[] value,String idPassword) {
// 指定认证模式为digest
Id id = new Id(AUTH_TYPE,idPassword);
// 创建的节点有所有权限
ACL acl = new ACL(ZooDefs.Perms.ALL,id);
try {
zk.create(path, value, Collections.singletonList(acl), CreateMode.PERSISTENT);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private String getNodeValue(String path,String idPassword) {
try {
// 由于创建节点时指定了权限,所以这里必须设置权限才能查询
// 注意:这里auth是不用加密的。
zk.addAuthInfo(AUTH_TYPE,AUTH_ID_PWD.getBytes());
return new String(zk.getData(path,false,null));
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
private void closeZK() {
if (null != zk) {
try {
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ZkTest1 zkTest1 = new ZkTest1();
try {
String idPassword = DigestAuthenticationProvider.generateDigest(AUTH_ID_PWD);
// 创建根节点
zkTest1.createNode(ZK_ROOT,"abc".getBytes(),idPassword);
String rootValue = zkTest1.getNodeValue(ZK_ROOT,idPassword);
if (StringUtils.isNotEmpty(rootValue)) {
System.out.println(ZK_ROOT + "节点创建成功!value=" + rootValue);
}
// 创建url节点
zkTest1.createNode(ZK_URL,"10.10.1.19".getBytes(),idPassword);
String urlValue = zkTest1.getNodeValue(ZK_URL,idPassword);
if (StringUtils.isNotEmpty(urlValue)) {
System.out.println(ZK_URL + "节点创建成功!value=" + urlValue);
}
// 创建username节点
zkTest1.createNode(ZK_USERNAME,"root".getBytes(),idPassword);
String usernameValue = zkTest1.getNodeValue(ZK_USERNAME,idPassword);
if (StringUtils.isNotEmpty(urlValue)) {
System.out.println(ZK_USERNAME + "节点创建成功!value=" + usernameValue);
}
// 创建password节点
zkTest1.createNode(ZK_PWD,"123456".getBytes(),idPassword);
String pwdValue = zkTest1.getNodeValue(ZK_PWD,idPassword);
if (StringUtils.isNotEmpty(pwdValue)) {
System.out.println(ZK_PWD + "节点创建成功!value=" + pwdValue);
}
zkTest1.closeZK();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

读取zookeeper配置的类

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
* Created by j.tommy on 2017/9/8.
*/
public class ZKTest2 {
private final static String ZK_CONNECTION_STR = "192.168.74.125:2181";
private final static int SESSION_TIMEOUT = 30000;
private final static String ZK_ROOT = "/dbConf";
private final static String ZK_URL_PATH = ZK_ROOT+"/url";
private final static String ZK_USERNAME_PATH = ZK_ROOT+"/username";
private final static String ZK_PASSWD_PATH = ZK_ROOT+"/password";
private final static String AUTH_TYPE = "digest";
private final static String AUTH_PASSWD = "admin:abc1";
private String url;
private String username;
private String password;
private ZooKeeper zk = null;
private ZooKeeper getZK() throws IOException, InterruptedException {
zk = new ZooKeeper(ZK_CONNECTION_STR,SESSION_TIMEOUT,new MyWatcher());
while (zk.getState() != ZooKeeper.States.CONNECTED) {
Thread.sleep(1000L);
}
zk.addAuthInfo(AUTH_TYPE,AUTH_PASSWD.getBytes());
return zk;
}
private void getZKValue() {
try {
this.url = new String(zk.getData(ZK_URL_PATH,true,null));
this.username = new String(zk.getData(ZK_USERNAME_PATH,true,null));
this.password = new String(zk.getData(ZK_PASSWD_PATH,true,null));
} catch (Exception e) {
e.printStackTrace();
}
}
class MyWatcher implements Watcher {
@Override
public void process(WatchedEvent watchedEvent) {
Event.EventType eventType = watchedEvent.getType();
if (eventType == Event.EventType.None) {
System.out.println("服务器连接成功");
}
else if (eventType == Event.EventType.NodeCreated) {
System.out.println("节点创建成功");
}
else if (eventType == Event.EventType.NodeDataChanged) {
System.out.println("数据修改成功");
getZKValue();
}
else if (eventType == Event.EventType.NodeDeleted) {
System.out.println("节点删除成功");
}
else if (eventType == Event.EventType.NodeChildrenChanged) {
System.out.println("子节点数据修改成功");
getZKValue();
}
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static void main(String[] args) throws InterruptedException, IOException, NoSuchAlgorithmException {
ZKTest2 zkTest2 = new ZKTest2();
ZooKeeper zk = zkTest2.getZK();
String auth = DigestAuthenticationProvider.generateDigest(AUTH_PASSWD);
System.out.println("auth:" +auth);
int loopCount = 10;
int i=0;
while (i < loopCount) {
zkTest2.getZKValue();
System.out.println("url:" + zkTest2.getUrl());
System.out.println("username:" + zkTest2.getUsername());
System.out.println("password:" + zkTest2.getPassword());
System.out.println("--------------------------------------");
i++;
Thread.sleep(5000L);
}
zk.close();
}
}

代码中,创建节点时使用的是digest认证,id和password为admin:123456,但读取时为admin:abc1.
这个时候运行程序是会出错的,如下:

提示没有权限,将读取配置类中id和password修改为与创建节点的一样(admin:123456),再次运行。

创建节点时id与password是要经过加密的,即DigestAuthenticationProvider.generateDigest(AUTH_PASSWD);但是验证时不需要。
同时在zookeeper的客户端中执行命令创建节点时,使用明文密码时可以创建成功的,但没法验证成功。

zookeeper客户端中,使用$ZOOKEEPER_HOME/bin/zkCli.sh -server zookeeper服务器IP:端口连接zookeeper服务器。
输入help查看所有命令:

zookeeper权限验证:http://blog.csdn.net/cainiaoxiaozhou/article/details/52954851
zookeeper客户端api操作:https://www.2cto.com/kf/201610/558610.html
http://www.cnblogs.com/ggjucheng/p/3370359.html

Donny wechat
欢迎关注我的个人公众号
打赏,是超越赞的一种表达。
Show comments from Gitment