ZooKeeper(二)Java客户端API

ZooKeeper(二)Java客户端API

一. 创建会话

通过构建一个ZooKeeper对象来创建会话,这是一个异步过程,构造函数会在处理完客户端初始化后立即返回,此时会话处于CONNECTING状态。会话真正创建完毕后,服务端向客户端发送一个事件通知。

1
2
3
4
5
// 构造函数API
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly);

实例代码如图:重写了process方法负责处理收到的Watcher通知,收到服务端发送的SyncConnected事件后,解除主程序在CountDownLatch上的等待阻塞。

复用sessionId,维持之前会话:

二. 创建节点

1
2
3
4
5
// 同步创建节点
String create(final String path, byte data[], List<ACL> acl, CreateMode createMode);

// 异步创建节点
void create(final String path, byte data[], List<ACL> acl, CreateMode createMode, StringCallback cb, Object ctx);

ZooKeeper节点内容只支持字节数组类型(byte[]),即ZooKeeper不负责为节点内容进行序列化,需要开发人员自己使用序列化工具操作。

默认不需要关注权限参数,只需在acl中传入 Ids.OPEN_ACL_UNSAFE ,表示不受权限控制。

创建同步节点,分别创建临时节点和临时顺序节点,二者返回值不一样。

创建异步节点,只需要实现 AsyncCallback.StringCallback() 接口即可。

AsyncCallback包括七种不同的回调接口:

  • StatCallback
  • DataCallback
  • ACLCallback
  • ChildrenCallback
  • Children2Callback
  • StringCallback
  • VoidCallback

同步接口调用过程需要关注抛出异常的可能,异步接口本身不抛出异常,素有异常都在回调函数中通过响应码(Result Code)体现。

三. 删除节点

ZooKeeper只允许删除叶子节点,即如果节点存在子节点就无法被直接删除。

1
2
3
public void delete(final String path, int version);

public void delete(final String path, int version, VoidCallback cb, Object ctx);

四. 读取数据

(1)getChildren

获取一个节点下的所有子节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<String> getChildren(final String path, Watcher watcher);

List<String> getChildren(String path, boolean watcher);

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

void getChildren(String path, boolean watcher, ChildrenCallback cb, Object ctx);

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

List<String> getChildren(String path, boolean watcher, Stat stat);

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

void getChildren(String path, boolean watcher, Children2Callback cb, Object ctx);

当有子节点被添加或删除时,服务端会向客户端发送一个 NodeChildrenChanged(EventType.NodeChildrenChanged) 类型的事件通知。要注意该通知不包含最新的节点列表,客户端必须主动重新获取。

使用同步接口获取子节点列表:

注意,Watcher通知是一次性的,一旦触发一次通知,该Watcher就失效了,因此客户端需要反复注册Watcher。

使用异步接口获取子节点列表:

异步接口经常被应用在这样的使用场景:应用启动时获取一些配置信息,如“机器列表”,这些配置通常较大,并且不希望配置的获取影响应用的主流程。

(2)getData

获取一个节点的数据内容:

1
2
3
4
5
6
7
byte[] getData(final String path, Watcher watcher, Stat stat);

byte[] getData(String path, boolean watcher, Stat stat);

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

void getData(String path, boolean watcher, DataCallback cb, Object ctx);

当节点的状态发生变更,ZooKeeper服务端向客户端发送一个 NodeDataChanged(EventType.NodeDataChanged) 的事件通知。节点的数据内容和数据版本变化都被看作是节点的变化。

五. 更新数据

1
2
3
Stat setData(final String path, byte data[], int version);

void setData(final String path, byte data[], int version, StatCallback cb, Object ctx);

getData 读取数据接口并未提供根据指定数据版本来获取数据的接口,setData 此处的version类似于CAS比较并交换原理,对应预期值表示针对此版本更新,这样在一个客户端读取并修改中间其他客户端的修改会使这次修改无效,从而避免并发问题。

分别使用不同的version进行了三次更新操作:数据版本从0开始,-1非合法的数据版本,这里用来告诉服务端,客户端要基于最新版本进行更新操作。第三次操作使用了之前的数据版本1所以导致更新失败。

六. 检测节点是否存在

检测节点是否存在,返回一个stat对象,当节点被创建、被删除或数据被更新会通过Watcher通知客户端:

1
2
3
4
5
6
7
public Stat exists(final String path, Watcher watcher);

public Stat exists(String path, boolean watcher);

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

public void exists(String path, boolean watcher, StatCallback cb, Object ctx);

上述示例中,先后进行了如下操作:

  1. 通过exists接口检测是否存在指定节点,同时注册了一个Watcher。
  2. 创建节点/zk-book,此时服务端马上会向客户端发送一个事件通知:NodeCreated。客户端收到该事件通知后,再次调用exists接口,同时注册Watcher。
  3. 更新该节点的数据,这个时候,服务端又会向客户端发送一个事件通知:NodeDataChanged。客户端收到该事件通知后,继续调用exists接口,同时注册Watcher。
  4. 创建子节点/zk-book/c1。
  5. 删除子节点/zk-book/c1。
  6. 删除节点/zk-book。此时客户端会收到服务端的事件通知:NodeDeleted。

综上所述,可以得知:

  • 无论指定节点是否存在,通过调用exists接口都可以注册Watcher。
  • exists接口中注册的Watcher,能够对节点创建、节点删除和节点数据更新事件进行监听。
  • 对于指定节点的子节点的各种变化,都不会通知客户端。

七. 权限控制

集群模式下的ZooKeeper,不同的应用之间往往是不会存在共享数据的使用场景的,因此需要解决不同应用之间的权限问题。

通过设置服务端上数据节点的ACL,来控制客户端对该节点的访问权限。ZooKeeper提供了多种权限控制模式:

  • world
  • auth
  • digest:主要讲解该模式
  • ip
  • super

客户端在会话创建后,调用 addAuthInfo(String scheme, byte[] auth) 接口进行权限信息的设置:


参考:

🔗 《从Paxos到Zookeeper-分布式一致性原理与实践》