5.zookeeper javaAPI

znode是zooKeeper集合的核心组件,zookeeper API提供了一小组方法使用 zookeeper集合来操纵znode的所有细节。

客户端应该遵循以步骤,与zookeeper服务器进行清晰和干净的交互。

  • 连接到zookeeper服务器,zookeeper服务器为客户端分配会话ID(sessionId)。
  • 定期向服务器发送心跳。否则,zookeeper服务器将过期会话ID,客户端需要重新连接。
  • 只要会话ID处于活动状态,就可以获取/设置znode。
  • 所有任务完成后,断开与zookeeper服务器的连接。如果客户端长时间不活动,则zookeeper服务器将自动断开客户端。

maven依赖

<dependencies>
        <!--zookeeper核心依赖-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.2</version>
        </dependency>

        <!--junit测试工具依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

zookeeper API

  1. ZooKeeper构造函数
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher);
  • connectString:连接到zookeeper主机,格式:ip + port。
  • sessionTimeout:会话超时时长,单位毫秒。
  • watcher:监视器对象。由于zookeeper API连接zookeeper服务是异步连接的,所以通过监控器来监听连接服务状态。
package com.huazai.zookeeper.zkexample.config;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.util.concurrent.CountDownLatch;

/**
 * @author pyh
 * @date 2021/5/19 0:20
 */
public class ZookeeperConnection {
    public static void main(String[] args) {
        connect();
    }

    public static ZooKeeper zooKeeper;

    public static ZooKeeper connect() {
        try {
            // 由于连接zookeeper服务器是异步连接,需要CountDownLatch阻塞主线程,等待子线程连接结果后反馈给主线程
            CountDownLatch countDownLatch = new CountDownLatch(1);
            /*
                connectString:服务器的ip和端口
                sessionTimeout:客户端与服务器之间的会话超时时间,以毫秒为单位的
                watcher:监视器对象
            */
            zooKeeper = new ZooKeeper("192.168.64.129:2181", 5000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                        System.out.println("zookeeper异步连接成功");
                    } else if (watchedEvent.getState() == Event.KeeperState.Disconnected) {
                        System.out.println("断开连接");
                    } else if (watchedEvent.getState() == Event.KeeperState.Expired) {
                        System.out.println("会话超时");
                    } else if (watchedEvent.getState() == Event.KeeperState.AuthFailed) {
                        System.out.println("认证失败");
                    } else if (watchedEvent.getState() == Event.KeeperState.Closed) {
                        System.out.println("连接关闭");
                    }
                    countDownLatch.countDown();
                }
            });
            // 主线程阻塞等待连接对象的创建成功
            countDownLatch.await();
            // 会话编号
            System.out.println("客户端sessionId:" + zooKeeper.getSessionId());
            return zooKeeper;
        } catch (Exception e) {
            System.out.println("zookeeper连接异常");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭zookeeper会话
     */
    public static void close() {
        if (zooKeeper != null) {
            try {
                zooKeeper.close();
                System.out.println("zookeeper关闭成功");
            } catch (InterruptedException e) {
                System.out.println("zookeeper关闭失败");
                e.printStackTrace();
            }
        }
    }
}
  1. create新增节点方法
// 同步方法
public String create(final String path, byte[] data, List<ACL> acl, CreateMode createMode);

// 异步方法
public void create(final String path, byte[] data, List<ACL> acl, CreateMode createMode, StringCallback cb, Object ctx);
  • path:znode路径。例如,/node1 /node11/node111。
  • data:要存储在指定znode路径中的数据。
  • acl:要创建的节点的访问控制列表。zookeeper API提供了一个静态接口 ZooDefs.Ids 来获取一些基本的acl列表。例如,ZooDefs.Ids.OPEN_ACL_UNSAFE 返回开放的znode的acl列表。
  • createMode:节点的类型,这是一个枚举。
  • callBack:异步回调接口。
  • ctx:传递上下文参数。
    一共有create六个重载方法,其中带StringCallback形参的为异步新增节点方法,不带的为同步新增节点方法,其中三个为同步方法,三个异步方法。同步新增节点的重载方法返回值为成功创建节点后的路径。
package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * @author pyh
 * @date 2021/5/19 0:53
 */
public class ZKCreate {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试同步新增节点方法
     *
     * @throws Exception
     */
    @Test
    public void createSync() throws Exception {
        /*
            path:节点的路径
            data:节点的数据
            acl:权限列表 world:anyone:cdrwa
            createMode:节点类型,持久化节点
         */
        String nodePath = zooKeeper.create("/createSync", "createSync".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println(nodePath);   // /createSync
    }

    /**
     * 测试新增节点的自定义world授权模式权限列表
     *
     * @throws Exception
     */
    @Test
    public void createCustomAclForWorld() throws Exception {
        // 权限列表集合
        List<ACL> acls = new ArrayList<>();
        // 入参分别为授权模式和授权对象
        Id id = new Id("world", "anyone");

        // 权限列表
        acls.add(new ACL(ZooDefs.Perms.READ, id));  // world:anyone:r
        acls.add(new ACL(ZooDefs.Perms.WRITE, id)); // world:anyone:w
        String nodePath = zooKeeper.create("/createCustomAclForWorld", "createCustomAclForWorld".getBytes(), acls, CreateMode.PERSISTENT);
        System.out.println(nodePath);   // /createCustomAclForWorld
    }

    /**
     * 测试新增节点的自定义ip授权模式权限列表
     *
     * @throws Exception
     */
    @Test
    public void createCustomAclForIp() throws Exception {
        // 权限列表集合
        List<ACL> acls = new ArrayList<>();
        // 入参分别为授权模式和授权对象
        Id id = new Id("ip", "192.168.64.129");

        // 权限列表
        acls.add(new ACL(ZooDefs.Perms.ALL, id));  // ip:192.168.64.129:crdwa
        acls.add(new ACL(ZooDefs.Perms.WRITE, id)); // ip:192.168.64.129:w
        String nodePath = zooKeeper.create("/createCustomAclForId", "createCustomAclForId".getBytes(), acls, CreateMode.PERSISTENT);
        System.out.println(nodePath);   // /createCustomAclForWorld
    }

    /**
     * 测试新增节点的auth授权模式权限列表
     *
     * @throws Exception
     */
    @Test
    public void createAuth() throws Exception {
        // 添加授权用户
        zooKeeper.addAuthInfo("digest", "huazai:123456".getBytes());    // addauth digest huazai:123456
        /*
            若应用auth授权模式,必须使用CREATOR_ALL_ACL常量,不能使用OPEN_ACL_UNSAFE,
            因为CREATOR_ALL_ACL指定的是授权为auth,OPEN_ACL_UNSAFE指向的授权模式是world,底层源码中可以看到
         */
        String nodePath = zooKeeper.create("/createAuth", "createAuth".getBytes(),
                ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
        System.out.println(nodePath);
    }

    /**
     * 测试新增节点的自定义auth授权模式权限列表
     *
     * @throws Exception
     */
    @Test
    public void createCustomAclForAuth() throws Exception {
        // 添加授权用户
        zooKeeper.addAuthInfo("digest", "huazai:123456".getBytes());    // addauth digest huazai:123456
        // 权限列表
        List<ACL> acls = new ArrayList<ACL>();
        // 授权模式和授权对象
        Id id = new Id("auth", "huazai");
        // 权限设置
        acls.add(new ACL(ZooDefs.Perms.READ, id));  // auth:huazai:r
        String nodePath = zooKeeper.create("/createCustomAclForAuth", "createCustomAclForAuth".getBytes(), acls, CreateMode.PERSISTENT);
        System.out.println(nodePath);
    }

    /**
     * 测试新增节点的自定义digest授权模式权限列表
     *
     * @throws Exception
     */
    @Test
    public void createCustomAclForDigest() throws Exception {
        // 权限列表
        List<ACL> acls = new ArrayList<ACL>();
        // 授权模式和授权对象
        // 密文生成格式:echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
        Id id = new Id("digest", "huazai:gb3+BhkHKjQhm0YiyONAAoQUKpc=");
        // 权限设置
        acls.add(new ACL(ZooDefs.Perms.ALL, id));   // digest:huazai:123456:crdwa
        String nodePath = zooKeeper.create("/createCustomAclForDigest", "createCustomAclForDigest".getBytes(), acls, CreateMode.PERSISTENT);
        System.out.println(nodePath);
    }

    /**
     * 测试新增持久化有序节点
     *
     * @throws Exception
     */
    @Test
    public void createPersistenSequential() throws Exception {
        // 创建节点同时指定权限,
        // 等价于:create -s /createPersistenSequential "createPersistenSequential" "world:anyone:crdwa"
        String nodePath = zooKeeper.create("/createPersistenSequential", "createPersistenSequential".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        // 成功创建后节点路径为带序号的节点路径,而不是自己指定的路径
        System.out.println(nodePath);
    }

    /**
     * 测试新增临时节点
     *
     * @throws Exception
     */
    @Test
    public void createEphemeral() throws Exception {
        // 创建节点同时指定权限,
        // 等价于:create -e /createEphemeral "createEphemeral" "world:anyone:crdwa"
        String nodePath = zooKeeper.create("/createEphemeral", "createEphemeral".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        // 由于创建的是临时节点,只在当前会话有效,所以创建之后自己到虚拟机是查询不到该节点数据
        System.out.println(nodePath);
    }

    /**
     * 测试新增临时有序节点
     *
     * @throws Exception
     */
    @Test
    public void createEphemeralSequential() throws Exception {
        // 创建节点同时指定权限,
        // 等价于:create -e -s /createEphemeral "createEphemeral" "world:anyone:crdwa"
        String nodePath = zooKeeper.create("/createEphemeralSequential", "createEphemeralSequential".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        // 由于创建的是临时节点,只在当前会话有效,所以创建之后自己到虚拟机是查询不到该节点数据
        System.out.println(nodePath);
    }

    /**
     * 测试异步新增节点
     *
     * @throws Exception
     */
    @Test
    public void createAsync() throws Exception {
        zooKeeper.create("/createAsync", "createAsync".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT,
                new AsyncCallback.StringCallback() {
                    @Override
                    public void processResult(int rc, String path, Object ctx, String name) {
                        // 0 代表创建成功,状态码参考:org.apache.zookeeper.KeeperException.CodeDeprecated
                        System.out.println(rc);     // 0
                        // 节点的路径
                        System.out.println(path);   // /createAsync
                        // 节点路径
                        System.out.println(name);   // /createAsync
                        // 上下文对象
                        System.out.println(ctx);    // 我是上下文对象,在processResult回调方法中的ctx参数可以获取到我

                    }
                }, "我是上下文对象,在processResult回调方法中的ctx参数可以获取到我");

    }


    @After
    public void after() {
        ZookeeperConnection.close();
    }
}
  1. set设置节点数据
// 同步设置数据方法
public Stat setData(final String path, byte[] data, int version);

// 异步设置数据方法
public void setData(final String path, byte[] data, int version, StatCallback cb, Object ctx)
  • path:znode路径。
  • data:要存储在指定znode路径中的数据。
  • version:znode的当前版本,-1代表删除节点时不考虑版本信息。
  • cb:异步回调接口。
  • ctx:传递上下文参数。
package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author pyh
 * @date 2021/5/21 0:18
 */
public class ZKSet {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试同步设置节点数据,如果乐观锁版本不匹配,则修改失败,抛出异常
     */
    @Test
    public void setSync() throws Exception {
        // path:节点的路径
        // data:节点数据
        // version:乐观锁版本,-1代表版本号不作为修改条件
        // set /setSync "test" -v 1
        Stat stat = zooKeeper.setData("/setSync", "test".getBytes(), 1);
        // 返回值数据等价于:stat /setSync
        System.out.println(stat);
    }

    /**
     * 测试异步设置节点数据,如果乐观锁版本不匹配,则修改失败,抛出异常
     *
     * @throws Exception
     */
    @Test
    public void setASync() throws Exception {
        // set /setASync "test" -v 1
        zooKeeper.setData("/setASync", "test".getBytes(), 0,
                new AsyncCallback.StatCallback() {
                    @Override
                    public void processResult(int rc, String path, Object ctx, Stat stat) {
                        // 0 代表创建成功,状态码参考:org.apache.zookeeper.KeeperException.CodeDeprecated
                        System.out.println(rc);     // 0
                        // 节点的路径
                        System.out.println(path);   // /setASync
                        // 上下文对象
                        System.out.println(ctx);    // 我是上下文对象,在processResult回调方法中的ctx参数可以获取到我
                        System.out.println(stat);    // stat /setASync
                    }
                }, "我是上下文对象,在processResult回调方法中的ctx参数可以获取到我");
    }

    @After
    public void after() {
        ZookeeperConnection.close();
    }
}
  1. delete删除节点
// 同步删除节点方法
public void delete(final String path, int version);

// 异步删除节点方法
public void delete(final String path, int version, VoidCallback cb, Object ctx);
  • path:znode路径。
  • version:znode的当前版本,-1代表删除节点时不考虑版本信息。
  • cb:异步回调接口。
  • ctx:传递上下文参数。
package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author pyh
 * @date 2021/5/24 23:50
 */
public class ZKDelete {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试同步删除节点方法
     *
     * @throws Exception
     */
    @Test
    public void deleteSync() throws Exception {
        zooKeeper.delete("/hello", 0);
    }

    /**
     * 测试异步删除节点方法
     *
     * @throws Exception
     */
    @Test
    public void deleteAsync() throws Exception {
        zooKeeper.delete("/zk", 0, new AsyncCallback.VoidCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx) {
                // 0 代表创建成功,状态码参考:org.apache.zookeeper.KeeperException.CodeDeprecated
                System.out.println(rc);     // 0
                // 节点的路径
                System.out.println(path);   // /hello
                // 上下文对象
                System.out.println(ctx);    // 我是上下文对象,在processResult回调方法中的ctx参数可以获取到我
            }
        }, "我是上下文对象,在processResult回调方法中的ctx参数可以获取到我");
    }

    @After
    public void after() {
        ZookeeperConnection.close();
    }
}
  1. get获取节点数据
// 同步获取节点数据方法
public byte[] getData(String path, boolean watch, Stat stat);
public byte[] getData(final String path, Watcher watcher, Stat stat);

// 异步获取节点数据方法
public void getData(String path, boolean watch, DataCallback cb, Object ctx);
public void getData(final String path, Watcher watcher, DataCallback cb, Object ctx);
  • path:znode路径。
  • watch:是否使用连接对象中注册的监视器。
  • watcher:监视器对象。
  • stat:返回znode的元数据。
  • cb:异步回调接口。
  • ctx:传递上下文参数。

zookeeper无论同步或者异步方法都提供能拿到监视器对象的重载方法。

package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author pyh
 * @date 2021/5/25 0:06
 */
public class ZKGet {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试同步获取节点数据方法
     *
     * @throws Exception
     */
    @Test
    public void getSync() throws Exception {
        // 获取的节点属性保存在这里
        Stat stat = new Stat();
        // 获取节点数据
        byte[] data = zooKeeper.getData("/hadoop", false, stat);
        System.out.println(new String(data));
        System.out.println(stat);
    }

    /**
     * 测试异步获取数据方法
     *
     * @throws Exception
     */
    @Test
    public void getAsync() throws Exception {
        zooKeeper.getData("/hadoop", false, new AsyncCallback.DataCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
                if (rc == 0) {
                    // 成功获取节点/hadoop数据:hadoop
                    System.out.println("成功获取节点" + path + "数据:" + new String(data));
                }
                System.out.println(ctx);
                System.out.println(stat);
            }
        }, "我是上下文对象,在processResult回调方法中的ctx参数可以获取到我");
    }

    @After
    public void after() {
        ZookeeperConnection.close();
    }
}
  1. getChildren查询子节点数据方法
// 获取子节点同步方法,返回值是子节点路径列表
public List<String> getChildren(String path, boolean watch);

// 获取子节点异步方法
public void getChildren(String path, boolean watch, ChildrenCallback cb, Object ctx);
  • path:znode父节点路径。
  • watch:是否使用连接对象中注册的监视器。
  • cb:异步回调接口。
  • ctx:传递上下文参数。
package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

/**
 * @author pyh
 * @date 2021/5/25 0:31
 */
public class getChildren {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试获取子节点同步方法
     *
     * @throws Exception
     */
    @Test
    public void getChildrenSync() throws Exception {
        // 子节点路径
        List<String> list = zooKeeper.getChildren("/hadoop", false);
        for (String str : list) {
            System.out.println(str);
        }
    }

    /**
     * 测试获取子节点异步方法
     *
     * @throws Exception
     */
    @Test
    public void getChildrenAsync() throws Exception {
        zooKeeper.getChildren("/hadoop", false, new AsyncCallback.ChildrenCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, List<String> children) {
                if (rc == 0) {
                    // 成功获取节点/hadoop子节点,子节点数量:1
                    System.out.println("成功获取节点" + path + "子节点,子节点数量:" + children.size());
                }
                System.out.println(ctx);
            }
        }, "在processResult回调方法中的ctx参数可以获取到我");
    }

    @After
    public void after() {
        ZookeeperConnection.close();
    }

}
  1. exists判断节点是否存在方法
// 同步判断方法
public Stat exists(String path, boolean watch);

// 异步判断方法
public void exists(String path, boolean watch, StatCallback cb, Object ctx);
  • path:znode路径。
  • watch:是否使用连接对象中注册的监视器。
  • cb:异步回调接口。
  • ctx:传递上下文参数。
package com.huazai.zookeeper.zkexample;

import com.huazai.zookeeper.zkexample.config.ZookeeperConnection;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author pyh
 * @date 2021/5/25 0:28
 */
public class ZKExists {
    private ZooKeeper zooKeeper;

    @Before
    public void before() {
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 测试检测节点是否存在同步方法
     *
     * @throws Exception
     */
    @Test
    public void existsSync() throws Exception {
        Stat stat = zooKeeper.exists("/hadoop", false);
        System.out.println(stat);
    }

    /**
     * 测试检测节点是否存在异步方法
     *
     * @throws Exception
     */
    @Test
    public void existsAsync() throws Exception {
        zooKeeper.exists("/hadoop", false, new AsyncCallback.StatCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                System.out.println(rc);
                // /hadoop
                System.out.println(path);
                // 我是上下文对象,在processResult回调方法中的ctx参数可以获取到我
                System.out.println(ctx);
                System.out.println(stat);
            }
        }, "我是上下文对象,在processResult回调方法中的ctx参数可以获取到我");
    }


    @After
    public void after() {
        ZookeeperConnection.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NPException.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值