ZooKeeper开发实战

1,220 阅读4分钟

一、ZooKeeper类

Java语言版本的ZooKeeper主要通过org.apache.zookeeper.ZooKeeper这个类使用ZooKeeper服务。

ZooKeeper(connectString, sessionTimeout, watcher)
1. connectString: 使用逗号分隔的列表,每个ZooKeeper节点是一个host:ip对,host是机器名或者IP地址,port是ZooKeeper节点对客户端提供服务的端口号,客户端会任意选取connectString中的一个节点建立连接;
2. sessionTimeout: [session](https://juejin.cn/post/6844904145955078152#heading-12) timeout时间;
3. watcher: 用于接收来自ZooKeeper集群的事件。

栗子:

{

        private String connectString = "localhost:2181";
        private static int sessionTimeout = 2000;

        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {

                List<String> children = null;
                try {
                    children = zkClient.getChildren("/", true);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

    }

二、ZooKeeper主要方法

  • create(path, data, acl, flags):
    在一个给定路径创建znode,并在znode保存data[]的数据,flag指定znode的类型;
zkClient.create("/data", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  • delete(path, version):
    如果给定path上的znode的版本和给定的version匹配,删除znode;
  • exists(path, watch):
    判断给定path上的znode是否存在,并在znode设置一个watch;
  • getData(path, watch):
    返回给定path上的znode数据,并在znode设置一个watch;
  • setData(path, data, version):
    如果给定path上的znode的版本和给定的version匹配,就设置znode数据;
  • getChildren(path, watch):
    返回给定path上的znode数据,并在znode设置一个watch;
  • sync(path):
    把客户端session连接节点和leader节点进行同步。

2.1方法说明

  • 所有读取znode数据的API都可以设置一个watch用来监控znode的变化;
  • 所有更新znode数据的API都有两个版本:无条件更新版本和条件更新版本。当version为-1,为无条件更新。否则只有指定的version和znode当前的version一致,才会进行更新,这样的更新是条件更新;
  • 所有的方法都有同步和异步两个版本。同步版本的方法发送请求给ZooKeeper并等待服务器的响应。异步版本把请求放入客户端的请求队列,然后马上返回。异步版本通过callback来接受来自服务端的响应。

2.2 数据读取API-getData栗子

getData(String path, boolean watch, Stat stat)
同步方法。如果watch为true,该znode的状态变化会发送给构建ZooKeeper时指定的watcher。
getData(final String path, Watcher watcher, DataCallback cb, Object ctx)
异步方法。watcher用来接收该znode的状态变化。 getData(String path, boolean watch, DataCallback cb, Object ctx)
异步方法。cb是一个callback,用来接收服务端的响应。ctx是提供给cb的context。如果watch为true,该znode的状态变化会发送给构建ZooKeeper时指定的watcher。

2.3 数据写入API-栗子

setData(final String path, byte data[], int version)
同步版本。如果version=-1,做无条件更新。如果version是非负整数,做条件更新。
setData(final String path, byte data[], int version, StatCallback cb, Object ctx)
异步版本。

2.3 watch

watch提供一个让客户端获取最新数据的机制。如果没有watch机制,客户端需要不断的轮询ZooKeeper来查看是否有数据更新,这在分布式环境中是非常耗时的。客户端可以在读取数据的时候设置一个watcher,这样在数据更新时,客户端就会收到通知

2.4 条件更新

在上图中,

  1. 客户端1把/data更新到版本1,实现/data的自增,如步骤1所示;
  2. 客户端2把/data更新到版本2,实现/data的自增,如步骤2所示;
  3. 客户端1不知道 /data已经被客户端2更新过了,还用过时的版本1去更新/data,此时更新失败(报错version No is not valid : /data)。假如客户端1使用的是无条件更新,/data就会更新为2,没有实现自增。

使用条件更新可以避免对数据基于过期的数据进行数据更新操作。

三、ZooKeeper代码异常处理

所有同步执行的API方法都有可能抛出以下两个异常:

  1. KeeperException:
    表示ZooKeeper服务端出错。
    KeeperException的子类ConnectionLossException表示客户端和当前连接的ZooKeeper节点断开了连接。网络分区和ZooKeeper节点失败都会导致这个异常出现。发生此异常的时机可能是在ZooKeeper节点处理客户端请求之前,也可能是在ZooKeeper处理客户端请求之后。当出现此异常之后,客户端会进行自动重新连接,但是我们必须要检查我们以前的客户端请求是否被成功执行。
  2. InterruptedException:
    表示方法被中断了。
    我们可以使用Thread.interrupt()来中断API的执行。