Java操作Zookeeper节点

1. Java操作ZooKeeper

引入jar包:

<dependency>
    <groupId>org.apache.zookeepergroupId>
    <artifactId>zookeeperartifactId>
    <version>3.4.10version>
dependency>
private ZooKeeper zk;

/**
 * 创建连接
 *
 * @param address        地址 集群写多个,逗号分开docker.vm.com:2181,docker.vm.com:2182,docker.vm.com:2183
 * @param sessionTimeout 会话过期时间
 */
public void createConnection(String address, int sessionTimeout) {
    try {
        zk = new ZooKeeper(address, sessionTimeout, new Watcher() {
            // 监控所有被触发的事件
            public void process(WatchedEvent event) {
                System.out.println("已经触发了" + event.getType() + "事件!");
                //1、获取事件状态
                Event.KeeperState state = event.getState();
                //2、获取事件类型
                Event.EventType type = event.getType();
                //获取节点地址
                String path = event.getPath();
                //3、判断是否连接
                if (Event.KeeperState.SyncConnected == state) {
                    //4、判断类型
                    if (Event.EventType.None == type) {
                        System.out.println("###zookeeper建立连接成功###");
                    } else if (Event.EventType.NodeCreated == type) {
                        System.out.println("###Watcher监听的对应数据节点被创建###, 当前新增节点:" + path);
                    } else if (Event.EventType.NodeDataChanged == type) {
                        System.out.println("###Watcher监听的对应数据节点的数据内容发生变更###, 当前节点:" + path + ",被修改...");
                    } else if (Event.EventType.NodeChildrenChanged == type) {
                        System.out.println("###Wather监听的对应数据节点的子节点列表发生变更###, 当前子节点:" + path + ",被修改...");
                    } else if (Event.EventType.NodeDeleted == type) {
                        System.out.println("###Watcher监听的对应数据节点被删除###, 当前节点:" + path + ",被删除...");
                    }
                }

            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}


/**
 * 判断指定节点是否存在
 *
 * @param path
 * @param needWatch
 * @return
 */
public Stat exist(String path, boolean needWatch) {
    try {
        return this.zk.exists(path, needWatch);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

/**
 * 创建持久化节点
 *
 * @param path
 * @param data
 * @return
 */
public boolean createNode(String path, String data) {
    try {
        this.exist(path, true);
        /**
         * acl:权限列表
         提供默认的权限OPEN_ACL_UNSAFE、CREATOR_ALL_ACL、READ_ACL_UNSAFE
         OPEN_ACL_UNSAFE:完全开放
         CREATOR_ALL_ACL:创建该znode的连接拥有所有权限
         READ_ACL_UNSAFE:所有的客户端都可读

         */
        /**
         * PERSISTENT 持久化节点
         * PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
         * EPHEMERAL 临时节点, 客户端session超时这类节点就会被自动删除
         * EPHEMERAL_SEQUENTIAL 临时自动编号节点
         */
        zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("###新增节点信息path:" + path + " data:" + data);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

/**
 * 修改持久化节点
 *
 * @param path
 * @param data
 * @return
 */
public boolean updateNode(String path, String data) {
    try {
        this.exist(path, true);
        //zk的数据版本是从0开始计数的。如果客户端传入的是-1,则表示zk服务器需要基于最新的数据进行更新。如果对zk的数据节点的更新操作没有原子性要求则可以使用-1.
        //version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
        zk.setData(path, data.getBytes(), -1);
        System.out.println("###修改节点信息path:" + path + " data:" + data);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

public boolean deleteNode(String path) {
    try {
        this.exist(path, true);
        zk.delete(path, -1);
        System.out.println("###删除节点信息path:" + path);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

public byte[] getNodeData(String path,boolean needWatch,Stat stat) {
    try {
        byte[] data = zk.getData(path, needWatch, stat);
        return data;
    } catch (KeeperException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return null;
}

public void close() {
    try {
        if (zk != null) {
            zk.close();
            System.out.println("###zookeeper服务已关闭");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) throws Exception {
    ZooTest test = new ZooTest();
    test.createConnection(ADDRESS, SESSION_TIMEOUT);
    test.createNode("/t1", "55555");
    test.updateNode("/test","3333");
    test.deleteNode("/test");
    test.close();
}

zookeeper的权限: ZooKeeper提供了如下几种验证模式(scheme):
• digest:Client端由用户名和密码验证,譬如user:password,digest的密码生成方式是Sha1摘要的base64形式
• auth:不使用任何id,代表任何已确认用户。 • ip:Client端由IP地址验证,譬如172.2.0.0/24
• world:固定用户为anyone,为所有Client端开放权限
• super:在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)

注意的是,exists操作和getAcl操作并不受ACL许可控制,因此任何客户端可以查询节点的状态和节点的ACL。
节点的权限(perms)主要有以下几种: • Create 允许对子节点Create操作 • Read
允许对本节点GetChildren和GetData操作 • Write 允许对本节点SetData操作 • Delete
允许对子节点Delete操作 • Admin 允许对本节点setAcl操作

ZooKeeper zk = new ZooKeeper("10.9.126.153", 3000, null);
List<ACL> acls = new ArrayList<ACL>(1);
Id id = new Id("digest", DigestAuthenticationProvider.generateDigest("admin:admin123"));
ACL acl = new ACL(ZooDefs.Perms.ALL, id);
//ACL acl = new ACL(ZooDefs.Perms.CREATE|ZooDefs.Perms.READ, id);//给多权限
acls.add(acl);
zk.create("/test", new byte[0], acls, CreateMode.PERSISTENT);
zk.addAuthInfo("digest", "admin:admin123".getBytes());
zk.close();

2. ZooKeeper基础

ZooKeeper是一个分布式应用程序协调服务。它监视集群中各个节点的状态,根据节点提交的反馈进行下一步合理操作。保证系统性能高效,功能稳定。
ZooKeeper客户端和server采用长连接。建立连接之后server生成64位的session
id给客户端。客户端定期发送ping包检查和保存于server的连接。一旦session结束或者超时,所有的临时节点被删除。客户端可以设置session超时时间。

2.1 ZooKeeper节点

ZooKeeper提供一个多层级(基于树形结构)的节点命名空间。类似于linux的目录结构,不同的是ZooKeeper每个节点都能存放数据,而linux文件系统中,只有文件中才能写数据,文件夹中只能放文件(ZooKeeper更简单,不区分文件和文件夹)。ZooKeeper中的节点不允许递归创建,即父节点不存在,不能创建子节点。如:

/parent_node/child

如果/parent_node不存在,则不能直接创建/parent_node/child
Zookeeper节点不能存放大量数据,每个节点存放数据上限为1M。 ZooKeeper节点有四种类型:
持久节点(PERSISTENT):在节点创建后就一直存在,直到有显示的删除操作来清除这个节点。不会随客户端会话失效而消失。如果创建节点时选择PERSISTENT,则不能有同名的节点存在,否则会报错:
在这里插入图片描述

持久顺序节点(PERSISTENT_SEQUENTIAL):这类节点也是持久的。ZooKeeper中每个父节点会为它的一级子节点维护一份时序,记录每个子节点的先后顺序。ZooKeeper会为每个节点添加一个数字(10位长度左边以0填充的递增数字)后缀作为新的节点名,数字范围是整型最大值。如创建两个/nodetest/child节点,/nodetest下的节点是:

Java操作Zookeeper节点_第1张图片

临时节点(EPHEMERAL):临时节点的生命周期与客户端会话绑定,如果创建节点的客户端会话失效(并不是断开连接),则节点就被清除掉。临时节点下不能创建子节点
临时顺序节点(EPHEMERAL_SEQUENTIAL):节点创建规则同持久顺序节点,只不过它是临时的。

2.2 Dubbo在ZooKeeper中的存储

Dubbo使用ZooKeeper作为注册中心,也是以节点的形式存储的: 根节点:在/dubbo下 一级节点时服务名(接口全路径)
二级节点下有四个子节点:consumers、configurators、routers、providers
Dubbo服务启动的时候会向/dubbo/${serviceName}/ providers下写入自己的URL地址,完成服务发布

2.3 ZooKeeper Watcher

客户端在向 ZooKeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchManager中。当ZooKeeper 服务器触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager的实现类中取出对应的 Watcher 对象来执行回调逻辑。
在这里插入图片描述

这个 Watcher 将作为整个 ZooKeeper会话期间的默认Watcher,会一直被保存在客户端 ZKWatchManager 的 defaultWatcher 中。另外,ZooKeeper
客户端也可以通过 getData、exists 和 getChildren 三个接口来向 ZooKeeper 服务器注册 Watcher。
无论是服务端还是客户端,一旦一个 Watcher 被触发,ZooKeeper 都会将其从相应的存储中移除。因此,在 Watcher的使用上是单次的,需要反复注册。这样的设计有效地减轻了服务端的压力。 触发Watcher回调的条件:
a) 客户端建立连接、断开连接
b) 节点数据发生变化
c) 节点本身发生变化

Java操作Zookeeper节点_第2张图片

你可能感兴趣的:(java技术,java,java-zookeeper,zookeeper)