zookeeper客户端api操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qincidong/article/details/82803471

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

客户端创建Zookeeper实例,然后调用这个类提供的方法与zookeeper服务器进行交互。
Zookeeper的构造函数有如下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读取的示例来说明
配置类:

/**
 * 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配置的类

/**
 * 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

猜你喜欢

转载自blog.csdn.net/qincidong/article/details/82803471