Zookeeper 基础

Zookeeper 基础(3.4.14)

概念

ZNode 的类型

类型 描述
持久节点 节点被创建后会一直存在服务器,直到主动删除。
临时节点 客户端会话结束,节点会被删除。临时节点不能创建子节点
持久顺序节点 创建后会在节点后加上一个数字后缀来表示顺序。
临时顺序节点 创建后会在节点后加上一个数字后缀来表示顺序。

ZNode 的状态

状态 描述
cZxid 节点被创建时的事务 ID。
ctime 节点创建时间。
mZxid 节点最后一次被修改时的事务 ID。
mtime 节点最后一次被修改时的时间。
pZxid 节点的子节点列表最后一次被修改时的事务 ID。
子节点列表更新是才更新,子节点中的内容更新不会更新。
cversion 子节点的版本号。
dataVersion 内容版本号。
aclVersion ACL 版本号。
ephemeralOwner 创建临时节点时的会话 sessionId,如果是持久节点值为 0。
dataLength 数据长度。
numChildren 直系子节点数。

命令行的基本使用

创建节点

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

  • -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 命令

ls path

# 查看某个路径下目录列表
ls /
> [personTemp0000000014, temp, zookeeper, person0000000013, user]
get 命令

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 命令

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

ACL 操作

  • scheme:代表采用的某种权限机制,包括 world、auth、digest、ip、super。
  • id:代表允许访问的用户。
  • permissions:权限组合字符串。

查询权限

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

ZkClient 操作 Zookeeper 的基本使用

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

Watcher 操作

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

Curator 操作 Zookeeper 的基本使用

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);

Watcher 操作

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

你可能感兴趣的:(zookeeper,java,后端)