前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Zookeeper Java API

Zookeeper Java API

作者头像
shysh95
发布2019-07-24 14:45:30
5270
发布2019-07-24 14:45:30
举报
文章被收录于专栏:shysh95shysh95

本文主要讲解使用Java API来和Zookeeper集群进行交互,大家在看完这篇文章以后一定要亲自动手去敲代码(纸上得来终觉浅,绝知此事要躬行)。下面介绍的API依赖的maven版本为:

代码语言:javascript
复制
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.14</version>
</dependency>
创建会话

客户端和Zookeeper创建会话的过程是一个异步的过程,构造方法在调用完成后立马返回Zookeeper,但此时绝大多数情况都还没有和服务端正式建立连接,处于CONNECTING的阶段。当连接建立完成后,将会向客户端发送一个事件通知告诉客户端连接建立完成。

代码语言:javascript
复制
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, 
        long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)
  • connectString:指定Zookeeper的服务器列表,多个服务器之间使用英文逗号分割,每个服务器节点的格式为host:port
  • sessionTimeout:会话超时时间,单位为ms。在设置的sessionTimeout时间内如果没有进行有效的心跳检测,会话将会失效
  • watcher:设置默认的Watcher事件通知处理器,可以为null
  • canBeReadOnly:标识当前会话是否支持只读模式。在Zookeeper集群中,如果一台机器和超过一半的机器失去网络连接,将不再提供读写服务。设置该参数为true,可以让这台服务器继续为客户端提供读请求。
  • sessionId和sessionPasswd:会话id和会话秘钥,两个参数共同确定一个会话,客户端可以使用这两个参数实现客户端会话复用。这两个值可以在第一次连接上服务器之后通过调用ZooKeeper实例的getSessionId()和getSessionPasswd()获取。
创建节点
代码语言:javascript
复制
/**
* 同步方式创建节点
*/
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:节点路径
  • data:节点存储的数据
  • acl:节点的Acl策略,如果没有策略要求,可以将该参数设置为ZooDefs.Ids.OPEN_ACL_UNSAFE
  • cb:注册一个回调函数。当服务端创建节点完成后,Zookeeper将会自动调用这个方法
  • ctx:用于传递一个对象,可以在回调方法执行的时候使用,通常是放一个上下文信息

讲个注意点:临时节点不允许有子节点。

下面看一下StringCallback的回调方法processResult:

代码语言:javascript
复制
public void processResult(int rc, String path, Object ctx, String name);
  • rc:响应码
  • path:接口调用时传入的节点路径参数
  • ctx:接口调用时传入的ctx参数
  • name:实际创建的节点的名称
删除节点
代码语言:javascript
复制
/**
* 同步删除节点
*/
public void delete(final String path, int version)
        throws InterruptedException, KeeperException

/**
* 异步删除节点
*/
public void delete(final String path, int version, VoidCallback cb,
            Object ctx)

参数的意义就不重复描述了,和创建节点的参数基本一致

读取子节点列表
代码语言:javascript
复制
public List<String> getChildren(final String path, Watcher watcher)
        throws KeeperException, InterruptedException

public List<String> getChildren(String path, boolean watch)
            throws KeeperException, InterruptedException

public void getChildren(final String path, Watcher watcher,
            ChildrenCallback cb, Object ctx)  

public void getChildren(String path, boolean watch, ChildrenCallback cb,
            Object ctx)

public List<String> getChildren(final String path, Watcher watcher,
            Stat stat)

public List<String> getChildren(String path, boolean watch, Stat stat)
            throws KeeperException, InterruptedException

public void getChildren(final String path, Watcher watcher,
            Children2Callback cb, Object ctx)

public void getChildren(String path, boolean watch, Children2Callback cb,
            Object ctx)
  • String path:指定数据节点的路径,获取该节点的所有子节点列表
  • Watcher watcher:注册的Watcher。一旦在此次获取子节点以后,如果子节点列表发生变更,该Watcher将会收到通知
  • boolean watch:表明是否需要注册一个Watcher,如果为true,则使用默认的watcher(在客户端创建会话的时候传入的Watcher),false则不使用watcher
  • ChildrenCallback cb:注册一个异步回调函数
  • Stat stat:传入一个旧的Stat信息,将会被替换为最新的Stat信息
  • Object ctx:用于传递的上下文对象

这里讲几个注意点:

  1. Watcher的注册只有一次有效果,也就是说Watcher在收到一次通知后将会失效,如果要保证Watcher一直有效,那么需要反复注册
  2. 假设子节点变更,Watcher必须要重新查询列表才能获取更新后的子节点列表
读取数据
代码语言:javascript
复制
public byte[] getData(final String path, Watcher watcher, Stat stat)
        throws KeeperException, InterruptedException

public byte[] getData(String path, boolean watch, Stat stat)
            throws KeeperException, InterruptedException

public void getData(final String path, Watcher watcher,
            DataCallback cb, Object ctx)


public void getData(String path, boolean watch, DataCallback cb, Object ctx)
  • String path:指定数据节点的路径,获取该节点存储的数据内容
  • boolean watch:表明是否需要注册一个Watcher,如果为true,则使用默认的Watcher(在客户端创建会话的时候传入的Watcher),false则不需要注册Watcher
  • DataCallback cb:注册一个异步回调函数
  • Watcher watcher:注册的Watcher。一旦在此次获取节点内容以后,如果节点内容发生变更,该Watcher将会受到通知
  • Stat stat:传入一个旧的Stat信息,将会被替换为最新的Stat信息
  • Object ctx:用于传递的上下文对象

这边讲一个注意点:即使节点的数据没有发生变化,但是如果dataVersion发生了变化,Watcher也会收到通知。

更新数据
代码语言:javascript
复制
public Stat setData(final String path, byte data[], int version)

public void setData(final String path, byte data[], int version,
            StatCallback cb, Object ctx)
  • String path:指定数据节点的路径,设置该节点的内容
  • byte data[]:节点新的数据内容
  • int version:数据版本,基于这个版本进行数据更新
  • StatCallback cb:注册一个异步回调函数
  • Object ctx:用于传递上下文的对象

下面我们看一下version这个参数,首先Zookeeper并不会存储多个版本的数据,那么这个version到底有什么用?

这个version和JAVA中的CAS理论相似(这里我默认大家都知道什么是CAS),假设一个客户端A基于上次获取的version对数据进行变更,如果在变更过程中有其他客户端对节点数据进行了变更,那么version和客户端A携带的version将会不一致更新失败。通过这一机制,我们很容易的解决了分布式高并发的更新问题。

version的值也可以为-1,虽然这是一个看似不合法的值,但-1是为了告诉Zookeeper服务器客户端需要基于对数据的最新版本进行更新。如果对Zookeeper节点的更新没有原子性要求,可以使用-1。

节点是否存在
代码语言:javascript
复制
public Stat exists(final String path, Watcher watcher)
        throws KeeperException, InterruptedException

public Stat exists(String path, boolean watch) throws KeeperException,
        InterruptedException

public void exists(final String path, Watcher watcher,
            StatCallback cb, Object ctx)

public void exists(String path, boolean watch, StatCallback cb, Object ctx)
  • String path:指定数据节点的路径,返回节点的属性信息,如果不存在则返回null
  • boolean watch:表明是否需要注册一个Watcher,如果为true,则使用默认的Watcher(在客户端创建会话的时候传入的Watcher),false则不需要注册Watcher
  • Watcher watcher:注册一个Watcher。用来监听以下事件:节点被创建、节点被删除、节点被更新
  • StatCallback cb:注册一个异步回调函数
  • Object ctx:用于传递上下文的对象
权限控制

如果想使用权限控制功能,那么需要在Zookeeper客户端创建之后,为Zookeeper客户端添加权限控制信息,API接口如下:

代码语言:javascript
复制
public void addAuthInfo(String scheme, byte auth[])
  • schema:权限控制模式,主要有以下几种:world、auth、digest、ip和super
  • auth[]:具体的权限信息

这边有个注意点:就是删除权限的控制比较特殊,当客户端对一个数据节点加了权限信息以后,对于删除操作而言,作用范围是子节点,但是这个节点本身还是可以自由删除的。

通过上面的讲述,我们可以看出使用原生的Zookeeper API还是比较复杂的,在上面我们还没有考虑关于Session重连等问题,因此我们很少直接使用原生的API与Zookeeper服务端进行交互,而是使用一些经过封装改良的客户端(例如ZkClient和Curator,这个后面讲),但是作为原生的API我们还是需要去了解的,因为封装改良的客户端其实最后还是使用的原生API进行操作的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建会话
  • 创建节点
  • 删除节点
  • 读取子节点列表
  • 读取数据
  • 更新数据
  • 节点是否存在
  • 权限控制
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档