zookeeper核心znode、watcher、ACL

前言

GitHub:https://github.com/yihonglei/ZooKeeper-Study

本文采用zk原生客户端方式对zk进行操作,对应github的zk-native项目。

maven引入jar包:

<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.14</version>
</dependency>

一 znode

1、 znode概述

ZooKeeper操作和维护的一个个数据称为znode,采用类似文件系统的层级树状结构进行管理。

2、znode四种类型

持久无序(PERSISTENT):节点创建后,如果不手动删除,节点一直存在,节点是无序的。

持久有序(PERSISTENT_SEQUENTIAL):持久,有序。

临时无序(EPHEMERAL):客户端session失效就会自动删除节点,节点无序。

临时有序(EPHEMERAL_SEQUENTIAL):临时,有序,

在创建节点时,需要指定节点类型。

3、znode节点数据

ZooKeeper的Stat对象中记录了节点数据,主要包括数据信息,版本,权限。

4、zkCli创建一个节点,查看数据

[zk: localhost:2181(CONNECTED) 33] create /lanhuigu 2019
Created /lanhuigu
[zk: localhost:2181(CONNECTED) 34] ls /lanhuigu
[]
[zk: localhost:2181(CONNECTED) 35] get /lanhuigu
2019
cZxid = 0x80000003b
ctime = Thu May 16 18:31:50 CST 2019
mZxid = 0x80000003b
mtime = Thu May 16 18:31:50 CST 2019
pZxid = 0x80000003b
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0

5、Stat数据结构说明

状态属性

说明

czxid

节点创建时的zxid

mzxid

节点最新一次更新发生时的zxid

ctime

节点创建时的时间戳

mtime

节点最新一次更新发生时的时间戳

dataVersion

 节点数据的更新次数

cversion

其子节点的更新次数

aclVersion

节点ACL(授权信息)的更新次数

ephemeralOwner

如果该节点为ephemeral节点, ephemeralOwner值表示与该节点绑定的session id。 如果该节点不是ephemeral节点,ephemeralOwner值为0。

dataLength

节点数据的字节数

numChildren

子节点个数

6、znode实例

ZooKeeper原生客户端对znode进行crud操作。

package com.lanhuigu.zookeeper.znode;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

/**
 * zookeeper使用原生方式连接,进行crud操作
 *
 * @auther: yihonglei
 * @date: 2019-05-11 21:43
 */
public class ZooKeeperCrud {
    private String connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";

    private ZooKeeper zk;

    public ZooKeeperCrud() {
        try {
            zk = new ZooKeeper(connectString, 5000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("监听器....");
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建持久无序节点
     */
    public String createPersistent(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 创建临时无序节点
     */
    public String createEphemeral(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }

    /**
     * 获取信息
     */
    public String getData(String path) throws KeeperException, InterruptedException {
        byte[] data = zk.getData(path, false, null);
        data = (data == null) ? "null".getBytes() : data;
        return new String(data);
    }

    /**
     * 更新信息
     */
    public Stat setData(String path, String data) throws KeeperException, InterruptedException {

        return zk.setData(path, data.getBytes(), -1);
    }

    /***
     * 判断节点是否存在
     */
    public Stat exists(String path) throws KeeperException, InterruptedException {

        return zk.exists(path, false);
    }

    /***
     * 删除节点
     */
    public void delete(String path) throws KeeperException, InterruptedException {

        zk.delete(path, -1);
    }

    /***
     * 递归删除节点
     */
    public void deleteRecursive(String path) throws KeeperException, InterruptedException {

        ZKUtil.deleteRecursive(zk, path);
    }

    /**
     * 测试代码
     */
    public static void main(String[] args) throws KeeperException, InterruptedException {
        ZooKeeperCrud crud = new ZooKeeperCrud();

        if (null != crud.exists("/lanhuigu")) {
            crud.delete("/lanhuigu");

            // 如果节点下还有节点数据,需要递归删除
            // crud.deleteRecursive("/lanhuigu");
        }

        crud.createPersistent("/lanhuigu", "2019");

        System.out.println(crud.getData("/lanhuigu"));
    }
}

7、代码说明

1)判断节点是否存在,如果存在,则删除掉;

2)创建一个持久节点/lanhuigu,节点数据为2019;

3)获取节点数据;

二 watcher

Watcher是ZooKeeper的事件监听器,ZooKeeper允许用户注册事件,当事件触发时服务端会通知到客户端,

客户端可以做相应的处理,该机制是Zookeeper实现分布式协调服务的重要特性。

KeeperState

EventType

触发条件

说明

操作

SyncConnected
(3)

None
(-1)

户端与服务端成功建立连接

此时客户端和服务器处于连接状态

NodeCreated(1)

Watcher监听的对应数据节点被创建

Create

NodeDeleted
(2)

Watcher监听的对应数据节点被删除

Delete/znode

NodeDataChanged
(3)

Watcher监听的对应数据节点的数据内容发生变更

setDate/znode

NodeChildChanged
(4)

Wather监听的对应数据节点的子节点列表发生变更

Create/child

Disconnected
(0)

None
(-1)

客户端与ZooKeeper服务器断开连接

此时客户端和服务器处于断开连接状态

Expired
(-112)

None
(-1)

会话超时

此时客户端会话失效,通常同时也会受到SessionExpiredException异常

AuthFailed
(4)

None
(-1)

通常有两种情况,1:使用错误的schema进行权限检查 2:SASL权限检查失败

通常同时也会收到AuthFailedException异常

1、watche实例

package com.lanhuigu.zookeeper.watcher;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

/**
 * zookeeper使用原生方式连接,watcher测试
 *
 * @auther: yihonglei
 * @date: 2019-05-11 21:43
 */
public class ZooKeeperWatcher implements Watcher {
    private String connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";

    private ZooKeeper zk;

    public ZooKeeperWatcher() {
        try {
            zk = new ZooKeeper(connectString, 5000, this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建持久无序节点
     */
    public String createPersistent(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 创建临时无序节点
     */
    public String createEphemeral(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }

    /**
     * 获取信息
     */
    public String getData(String path, boolean watcher) throws KeeperException, InterruptedException {
        byte[] data = zk.getData(path, watcher, null);
        data = (data == null) ? "null".getBytes() : data;
        return new String(data);
    }

    /**
     * 更新信息
     */
    public Stat setData(String path, String data) throws KeeperException, InterruptedException {

        return zk.setData(path, data.getBytes(), -1);
    }

    /***
     * 判断节点是否存在
     */
    public Stat exists(String path, boolean watcher) throws KeeperException, InterruptedException {

        return zk.exists(path, watcher);
    }

    /***
     * 删除节点
     */
    public void delete(String path) throws KeeperException, InterruptedException {

        zk.delete(path, -1);
    }

    /***
     * 递归删除节点
     */
    public void deleteRecursive(String path) throws KeeperException, InterruptedException {

        ZKUtil.deleteRecursive(zk, path);
    }

    /**
     * Watcher处理
     */
    @Override
    public void process(WatchedEvent event) {
        // 连接状态
        Event.KeeperState keeperState = event.getState();

        // 事件类型
        Event.EventType eventType = event.getType();

        // 受影响的path
        String path = event.getPath();

        System.out.println("连接状态:" + keeperState + ",事件类型:" + eventType + ",受影响的path:" + path);

        try {
            if (null != this.exists("/lanhuigu", true)) {
                System.out.println("内容:" + this.getData("/lanhuigu", true));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("==================");
    }

    /**
     * 测试代码
     */
    public static void main(String[] args) throws KeeperException, InterruptedException {
        ZooKeeperWatcher crud = new ZooKeeperWatcher();

        // 判断节点是否存在,存在则删除
        if (null != crud.exists("/lanhuigu", true)) {
            Thread.sleep(1000);

            crud.delete("/lanhuigu");

            // 注意:如果节点下还有节点数据,需要递归删除
            // crud.deleteRecursive("/lanhuigu");
        }

        // 创建持久无序节点
        crud.createPersistent("/lanhuigu", "2019");

        // 主线程休眠10秒,让子线程都执行完
        Thread.sleep(1000 * 1000);
    }
}

2、代码说明

1)ZooKeeperWatcher实现watcher接口,并实现process方法;

2)构造器创建ZooKeeper时注册监听;

3)当节点改变时,触发监听;

三 ACL

1、ACL(Access Control List)

内置的 ACL schemes:

world:默认方式,相当于全世界都能访问。


auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)。


digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。


ip:使用Ip地址认证。

 

2、ACL支持权限

CREATE: 能创建子节点。

READ:能获取节点数据和列出其子节点。

WRITE: 能设置节点数据。

DELETE: 能删除子节点。

ADMIN: 能设置权限。

 

3、查看节点所属权限

[zk: localhost:2181(CONNECTED) 13] getAcl /zookeeper

'world,'anyone

: cdrwa

4、ACL实例

package com.lanhuigu.zookeeper.acl;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

/**
 * zookeeper使用原生方式连接,进行acl测试
 *
 * @auther: yihonglei
 * @date: 2019-05-11 21:43
 */
public class ZooKeeperAcl {
    private String connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";

    private ZooKeeper zk;

    /**
     * 认证类型
     */
    private final static String scheme = "digest";
    private final static String auth = "root:123456";

    /**
     * flag 为true权限认证,否则,非权限认证
     */
    public ZooKeeperAcl(boolean flag) {
        try {
            zk = new ZooKeeper(connectString, 5000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("监听器......");
                }
            });
            if (flag) {
                zk.addAuthInfo(scheme, auth.getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建持久无序节点
     */
    public String createPersistent(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 创建持久无序节点(权限创建)
     */
    public String createPersistentAcl(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
    }

    /**
     * 创建临时无序节点
     */
    public String createEphemeral(String path, String data) throws KeeperException, InterruptedException {

        return zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }

    /**
     * 获取信息
     */
    public String getData(String path) throws KeeperException, InterruptedException {
        byte[] data = zk.getData(path, false, null);
        data = (data == null) ? "null".getBytes() : data;
        return new String(data);
    }

    /**
     * 更新信息
     */
    public Stat setData(String path, String data) throws KeeperException, InterruptedException {

        return zk.setData(path, data.getBytes(), -1);
    }

    /***
     * 判断节点是否存在
     */
    public Stat exists(String path) throws KeeperException, InterruptedException {

        return zk.exists(path, false);
    }

    /***
     * 删除节点
     */
    public void delete(String path) throws KeeperException, InterruptedException {

        zk.delete(path, -1);
    }

    /***
     * 递归删除节点
     */
    public void deleteRecursive(String path) throws KeeperException, InterruptedException {

        ZKUtil.deleteRecursive(zk, path);
    }

    /**
     * 测试代码
     */
    public static void main(String[] args) throws KeeperException, InterruptedException {
        // 1、权限认证(flag = true)
        ZooKeeperAcl acl = new ZooKeeperAcl(true);

        String path = "/lanhuiguAcl";

        if (null != acl.exists(path)) {
            acl.delete(path);

            // 如果节点下还有节点数据,需要递归删除
            // acl.deleteRecursive("/lanhuiguAcl");
        }

        acl.createPersistentAcl(path, "2019-acl");

        System.out.println("权限认证读取:" + acl.getData(path));

        // 2、非权限认证(flag = false)
        ZooKeeperAcl noAcl = new ZooKeeperAcl(false);

        System.out.println("非权限认证读取权限认证:" + noAcl.getData(path));

        // 命令客户端权限认证访问
        /**
         * [zk: localhost:2181(CONNECTED) 12] addauth digest root:123456
         * [zk: localhost:2181(CONNECTED) 13] get /lanhuiguAcl
         * 2019-acl
         * cZxid = 0x300000095
         * ctime = Sun May 12 22:26:19 CST 2019
         * mZxid = 0x300000095
         * mtime = Sun May 12 22:26:19 CST 2019
         * pZxid = 0x300000095
         * cversion = 0
         * dataVersion = 0
         * aclVersion = 0
         * ephemeralOwner = 0x0
         * dataLength = 8
         * numChildren = 0
         */
    }
}

5、代码运行

6、代码说明

1)在构造器设置权限级别,用户名和密码;

2)权限认证创建节点,权限认证能读,但是非权限认证去读的时候会报NoAuth错误;

3)zkCli访问时需要授权访问;

[zk: localhost:2181(CONNECTED) 12] addauth digest root:123456
[zk: localhost:2181(CONNECTED) 13] get /lanhuiguAcl
2019-acl
cZxid = 0x300000095
ctime = Sun May 12 22:26:19 CST 2019
mZxid = 0x300000095
mtime = Sun May 12 22:26:19 CST 2019
pZxid = 0x300000095
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
发布了502 篇原创文章 · 获赞 358 · 访问量 118万+

猜你喜欢

转载自blog.csdn.net/yhl_jxy/article/details/90269557
今日推荐