本文主要讲解使用Java API来和Zookeeper集群进行交互,大家在看完这篇文章以后一定要亲自动手去敲代码(纸上得来终觉浅,绝知此事要躬行)。下面介绍的API依赖的maven版本为:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
客户端和Zookeeper创建会话的过程是一个异步的过程,构造方法在调用完成后立马返回Zookeeper,但此时绝大多数情况都还没有和服务端正式建立连接,处于CONNECTING的阶段。当连接建立完成后,将会向客户端发送一个事件通知告诉客户端连接建立完成。
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,
long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)
/**
* 同步方式创建节点
*/
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)
讲个注意点:临时节点不允许有子节点。
下面看一下StringCallback的回调方法processResult:
public void processResult(int rc, String path, Object ctx, String name);
/**
* 同步删除节点
*/
public void delete(final String path, int version)
throws InterruptedException, KeeperException
/**
* 异步删除节点
*/
public void delete(final String path, int version, VoidCallback cb,
Object ctx)
参数的意义就不重复描述了,和创建节点的参数基本一致
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)
这里讲几个注意点:
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)
这边讲一个注意点:即使节点的数据没有发生变化,但是如果dataVersion发生了变化,Watcher也会收到通知。
public Stat setData(final String path, byte data[], int version)
public void setData(final 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。
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)
如果想使用权限控制功能,那么需要在Zookeeper客户端创建之后,为Zookeeper客户端添加权限控制信息,API接口如下:
public void addAuthInfo(String scheme, byte auth[])
这边有个注意点:就是删除权限的控制比较特殊,当客户端对一个数据节点加了权限信息以后,对于删除操作而言,作用范围是子节点,但是这个节点本身还是可以自由删除的。
通过上面的讲述,我们可以看出使用原生的Zookeeper API还是比较复杂的,在上面我们还没有考虑关于Session重连等问题,因此我们很少直接使用原生的API与Zookeeper服务端进行交互,而是使用一些经过封装改良的客户端(例如ZkClient和Curator,这个后面讲),但是作为原生的API我们还是需要去了解的,因为封装改良的客户端其实最后还是使用的原生API进行操作的。