类型 | 描述 |
---|---|
持久节点 | 节点被创建后会一直存在服务器,直到主动删除。 |
临时节点 | 客户端会话结束,节点会被删除。临时节点不能创建子节点。 |
持久顺序节点 | 创建后会在节点后加上一个数字后缀来表示顺序。 |
临时顺序节点 | 创建后会在节点后加上一个数字后缀来表示顺序。 |
状态 | 描述 |
---|---|
cZxid | 节点被创建时的事务 ID。 |
ctime | 节点创建时间。 |
mZxid | 节点最后一次被修改时的事务 ID。 |
mtime | 节点最后一次被修改时的时间。 |
pZxid | 节点的子节点列表最后一次被修改时的事务 ID。 子节点列表更新是才更新,子节点中的内容更新不会更新。 |
cversion | 子节点的版本号。 |
dataVersion | 内容版本号。 |
aclVersion | ACL 版本号。 |
ephemeralOwner | 创建临时节点时的会话 sessionId,如果是持久节点值为 0。 |
dataLength | 数据长度。 |
numChildren | 直系子节点数。 |
create [-s] [-e] path data acl
#持久节点
create /user zhangsan
> Created /user
#临时节点
create -e /temp hello
> Created /temp
#持久顺序节点
create -s /person no1
> Created /person0000000013
#临时顺序节点
create -e -s /personTemp zhangsan
> Created /personTemp0000000014
ls path
# 查看某个路径下目录列表
ls /
> [personTemp0000000014, temp, zookeeper, person0000000013, user]
get path [watch]
# 获取节点数据和状态信息
get /user
>
zhangsan
cZxid = 0x2ce
ctime = Sat Apr 09 16:27:38 CST 2022
mZxid = 0x2ce
mtime = Sat Apr 09 16:27:38 CST 2022
pZxid = 0x2ce
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
# 监控
# 第一个客户端
get /user watch
# 第二个客户端
set /user lisi
# 第一个客户端返回
> WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/user
stat path [watch]
# 查看节点状态信息
stat /user
delete path [version]
# 删除某节点
delete /user
# 只能删除空节点 若有子节点
Node not empty: /user
rmr path
# 删除路径下的所有节点
rmr /user
set path data [version]
# 修改节点存储的数据
set /user lisi
查询权限
getAcl /user
> 'world,'anyone
: cdrwa
添加用户
addauth digest root:123456
设置权限
setAcl /user auth:root:123456:cdraw
# 此时查询权限 getAcl /user
> 'digest,'root:u53OoA8hprX59uwFsvQBS3QuI00=
: cdrwa
# 下次访问
ls /user
> Authentication is not valid : /user
# 认证授权信息
addauth digest root:123456
pom.xml
<dependency>
<groupId>com.101tecgroupId>
<artifactId>zkclientartifactId>
<version>0.9version>
dependency>
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
// 持久节点
zkClient.createPersistent("/user");
// 临时节点
zkClient.createEphemeral("/temp");
// 持久顺序节点 返回值是顺序节点的 name
String name = zkClient.createPersistentSequential("/user", "lisi");
// 临时顺序节点 返回值是顺序节点的 name
String name = zkClient.createEphemeralSequential("/user", "zhangsan");
// 循环创建节点
zkClient.createPersistent("/person/class1", true);
// 删除当前节点
// 只能删除没有子节点的节点 NotEmptyException: KeeperErrorCode = Directory not empty for /person
boolean flag = zkClient.delete("/user0000000018");
// 递归删除
boolean flag = zkClient.deleteRecursive("/person");
// 修改节点数据
zkClient.writeData("/user", "zhangsan");
// 读取节点数据
String userName = zkClient.readData("/user");
zkClient 创建连接的时候指定了默认的序列化类。所以存储在节点上的值也是序列化后的字节数组。
当使用 zkCli.sh 在控制台 set 值时,存储的是普通的字符串字节数组。
当 set 值时虽然触发了值改变事件,但 zkClient 无法反序列化这个值。
要使 zkCli.sh 的值也能被 zkClient 读取必须通过实现 ZkSerializer 接口使用自定义的序列化类。
// 自定义序列化客户端
ZkClient zkClient = new ZkClient("127.0.0.1:2181",10000, 10000,new ZkSerializer() {
@Override
public byte[] serialize(Object data) throws ZkMarshallingError {
return String.valueOf(data).getBytes(StandardCharsets.UTF_8);
}
@Override
public Object deserialize(byte[] bytes) throws ZkMarshallingError {
return new String(bytes, StandardCharsets.UTF_8);
}
});
// 注册节点数据变更的监听
zkClient.subscribeDataChanges("/user", new IZkDataListener() {
@Override
public void handleDataChange(String path, Object data) throws Exception {
// 更改的节点路径
System.out.println(path);
// 修改后的值
System.out.println(data);
}
@Override
public void handleDataDeleted(String path) throws Exception {
System.out.println(path);
}
});
// 注册节点子节点变更的监听
zkClient.subscribeChildChanges("/user", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChild) throws Exception {
// /user 's child changed, currentChild:[class]
System.out.println(parentPath + " 's child changed, currentChild:" + currentChild);
}
});
pom.xml
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>2.12.0version>
dependency>
CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
// 命名空间 之后的节点操作都是针对 /base 目录下的
.namespace("base")
.build();
// 启动 client
client.start();
// 创建持久节点 返回值是路径
String path = client.create()
// 循环创建
.creatingParentContainersIfNeeded().forPath("/user/class", "hello".getBytes());
// 创建临时节点
String path = client.create().creatingParentContainersIfNeeded()
// 设置节点属性
.withMode(CreateMode.EPHEMERAL)
.forPath("/user/class", "hello".getBytes());
client.delete().deletingChildrenIfNeeded().forPath("/user");
// 返回值是节点状态
Stat stat = client.setData().forPath("/user/class", "no".getBytes());
// 读取节点内容并获取状态信息
Stat stat = new Stat();
byte[] bytes = client.getData().storingStatIn(stat).forPath("/user/class");
System.out.println(new String(bytes));
System.out.println(stat);
TreeCache nodeCache = new TreeCache(client, "/user1");
nodeCache.start();
// 添加监听回调事件
nodeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
// 发生改变的路径
System.out.println(treeCacheEvent.getData().getPath());
// 改变后的数据
System.out.println(new String(treeCacheEvent.getData().getData()));
}
});
参考git:https://gitee.com/zhangyizhou/learning-zookeeper-demo.git