Zookeeper客户端ZkClient

来源:互联网 发布:matlab求协方差矩阵 编辑:程序博客网 时间:2024/06/06 04:00

ZkClient简介

  1. ZkClient是github上开源的一个zookeeper客户端。它对原生的zookeeper客户端API进行了封装,内部实现了session重连,Watcher反复注册,极大降低了开发人员使用zookeeper的难度。

创建会话

  1. zkClient提供了7个构造方法来创建zookeeper会话。原生的zookeeper客户端API创建会话是异步过程,而zkClient将创建会话封装成同步过程。
  2. 看看构造函数:
2.1. public ZkClient(String serverstring)2.2. public ZkClient(String zkServers, int connectionTimeout)2.3. public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout)2.4. public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout, ZkSerializer zkSerializer)2.5. public ZkClient(IZkConnection connection)2.6. public ZkClient(IZkConnection connection, int connectionTimeout)2.7. public ZkClient(IZkConnection zkConnection, int connectionTimeout, ZkSerializer zkSerializer) 
  1. 参数详解:
    3.1. zkServers:连接字符串—[ ip:port,ip,port,ip:port]
    3.2. connectionTimeout—连接超时时间
    3.3. sessionTimeout—会话超时时间,默认30 000毫秒
    3.4. zkSerializer—序列化机制,默认采用JDK自带机制
    3.5. IZkConnection—对zookeeper接口最直接的封装。上述几种构造方式最终都是采用IZkConnection进行连接Zookeeper。

IZkConnection

  1. IZkConnection中封装了直接操作zookeeper的方法。包括连接zookeeper,创建节点,删除节点,查询节点内容,获取子节点列表等方法。
  2. IZkConnection接口包含两个实现类,ZkConnection和InMemoryConnection。常用的就是ZkConnection类,满足绝大部分场景使用。
  3. ZkConnection中连接zookeeper时,注册watcher。源码简单清晰:
public class ZkConnection implements IZkConnection {    /** 默认的session超时时间为30 000毫秒 */    private static final int DEFAULT_SESSION_TIMEOUT = 30000;    // zookeeper 引用    private ZooKeeper _zk = null;    // 定义锁对象    private Lock _zookeeperLock = new ReentrantLock();    // 连接zookeeper字符串    private final String _servers;    private final int _sessionTimeOut;    // 构造函数    public ZkConnection(String zkServers) {        this(zkServers, DEFAULT_SESSION_TIMEOUT);    }    public ZkConnection(String zkServers, int sessionTimeOut) {        _servers = zkServers;        _sessionTimeOut = sessionTimeOut;    }    /** 连接zookeeper方法,注册wathcer */    public void connect(Watcher watcher) {        // 加锁,保证只有一个客户端连接上即可        _zookeeperLock.lock();        try {            if (_zk != null) {                throw new IllegalStateException("zk client has already been started");            }            try {              // 原生的创建zookeeper连接                _zk = new ZooKeeper(_servers, _sessionTimeOut, watcher);            } catch (IOException e) {                throw new ZkException("Unable to connect to " + _servers, e);            }        } finally {            _zookeeperLock.unlock();        }    }   /**  关闭zookeeper连接  **/    public void close() throws InterruptedException {        _zookeeperLock.lock();        try {            if (_zk != null){                _zk.close();                _zk = null;            }        } finally {            _zookeeperLock.unlock();        }    }   // 创建节点    public String create(String path, byte[] data, CreateMode mode) throws KeeperException, InterruptedException {        return _zk.create(path, data, Ids.OPEN_ACL_UNSAFE, mode);    }   // 删除节点    public void delete(String path) throws InterruptedException, KeeperException {        _zk.delete(path, -1);    }  // 检查节点是否存在    public boolean exists(String path, boolean watch) throws KeeperException, InterruptedException {        return _zk.exists(path, watch) != null;    } // 获取当前节点的子节点列表    public List<String> getChildren(final String path, final boolean watch) throws KeeperException, InterruptedException {        return _zk.getChildren(path, watch);    }   // 读取节点数据内容    public byte[] readData(String path, Stat stat, boolean watch) throws KeeperException, InterruptedException {        return _zk.getData(path, watch, stat);    }  // 更新节点数据内容    public void writeData(String path, byte[] data) throws KeeperException, InterruptedException {        writeData(path, data, -1);    } // 更新节点数据内容,附带版本信息    public void writeData(String path, byte[] data, int version) throws KeeperException, InterruptedException {        _zk.setData(path, data, version);    } // 获取zookeeper状态    public States getZookeeperState() {        return _zk != null ? _zk.getState() : null;    }    public ZooKeeper getZookeeper() {        return _zk;    }    @Override    public long getCreateTime(String path) throws KeeperException, InterruptedException {        Stat stat = _zk.exists(path, false);        if (stat != null) {            return stat.getCtime();        }        return -1;    }    @Override    public String getServers() {        return _servers;    }}

创建节点

  1. 原生zookeeper的API创建node时,需要将数据内容先先进行序列化,而zkClient在构造连接时,已经制定了序列化方式(使用默认或者自行制定),直接传递对象即可。
  2. zkClient创建节点时,提供了可以单独创建持久节点,持久顺序节点,临时节点,临时顺序节点等方法。
// 创建持久化节点,内容默认为空2.1. public void createPersistent(String path)// 父节点不存在,可以先创建父节点,再创建子节点,内容默认为空2.2.  public void createPersistent(String path, boolean createParents)// 创建带有数据的节点2.3.  public void createPersistent(String path, Object data)// 创建持久化顺序节点2.4.   public String createPersistentSequential(String path, Object data)// 创建临时节点,数据默认为空2.5.  public void createEphemeral(final String path)// 创建临时节点,指定数据内容2.6.  public void createEphemeral(final String path, final Object data)// 创建临时顺序节点2.7.  public String createEphemeralSequential(final String path, final Object data)// 根据指定模式创建节点2.8.   public String create(final String path, Object data, final CreateMode mode)

查询节点内容

  1. zkClient中提供了3种获取节点内容的方法:zkClient再读取数据节点内容的时候,内部已经将字节对象反序列化了,因为在创建连接的时候需要指定序列化方式
// 读取当前节点数据内容,节点不存在抛出异常 1.1.  public <T extends Object> T readData(String path)// 读取当前节点数据内容,returnNullIfPathNotExists参数表明节点不存在不会抛出异常1.2.  public <T extends Object> T readData(String path, boolean returnNullIfPathNotExists)// 传入状态数值,服务端返回最新的状态1.3. public <T extends Object> T readData(String path, Stat stat)

更新节点

1.更新节点内容主要是封装了2个方法,

// 更新数据内容1.1. public void writeData(String path, Object object)// 根据传入的期望版本数值,更新节点数据内容,类似于CAS方式1.2. public void writeData(final String path, Object datat, final int expectedVersion)

删除节点

注册事件监听

  1. 在原生的zookeeper中,使用watcher需要每次先注册,而且使用一次就需要注册一次。而再zkClient中,没有注册watcher的必要,而是引入了listener的概念,即只要client在某一个节点中注册了listener,只要服务端发生变化,就会通知当前注册listener的客户端。
  2. zkClient中主要有3种listener事件可以注册,分别是节点发生变化,节点内容发生变化,状态发生变化。注册这三种listener,服务端可以主动通知客户端最新的数据。
  3. 原生的zookeeper中,服务端通知客户端之后,客户端需要重新去服务器上获取最新的数据内容
    这里写图片描述

事件监听接口

1.zkClient提供了三种事件监听接口,分别是:
1.1. IZkDataListener :当前节点数据内容或版本发生变化或者当前节点被删除,触发当前接口
1.2. IZkChildListener: 节点列表变化事件监听,即当前节点的子节点发生变化(删除)或子节点列表发生变化(新增或删除),触发当前接口
1.3. IZkStateListener:zookeeper连接状态发生变化时,触发该接口,这个在zkClient连接zookeeper时,用到比较多。
2. IZkDataListener

/**详述:client向某个节点注册该listener后,如果该节点的数据内容发生变化,则服务 端通过该接口通知客户端。还有另外一种情况,如果当前节点不存在时,如果创建了该节点,也会发生通知**/public interface IZkDataListener {    /**dataPath:当前数据节点    ** data:服务端传递过来最新节点数据内容,不需要重新去服务端重新获取    */    public void handleDataChange(String dataPath, Object data) throws Exception;    /**删除当前节点,触发该接口通知。此时,dataPath即当前节点路径*/    public void handleDataDeleted(String dataPath) throws Exception;}
  1. 注册数据节点listener
 // 调用该方法可以将listener注册到某一个节点,监听某一个节点数据内容的变化 3. 1. public void subscribeDataChanges(String path, IZkDataListener listener) // 调用该方法可以当前节点path上的监听解除 3. 2.  public void unsubscribeDataChanges(String path, IZkDataListener dataListener)3.3. 使用方式/**     * IZkDataListener接口主要有两个方法:     * ---handleDataChange(dataPath,data)     * ---handleDataDeleted(dataPath)     * @param parentPath     */    public void listenDataChange(String currentPath){        zkClient.subscribeDataChanges(currentPath,new IZkDataListener(){            public void handleDataChange(String dataPath, Object data)                    throws Exception {                 System.out.println("dataPath="+dataPath+",data = "+data);            }            public void handleDataDeleted(String dataPath) throws Exception {                 System.out.println("deleted node = "+dataPath);            }});    }
  1. IZkChildListener接口
1. public interface IZkChildListener {    /**     * Called when the children of the given path changed.     * @param parentPath:父节点,即监听的是parentPath子节点     * @param currentChilds     *        parentpath删除,返回null.存在,返回最新的子节点列表,不需要重新去获取最新的子节点列表     */    public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception;}

5.注册IZkChildListener

// 注册节点变化listener5.1 public List<String> subscribeChildChanges(String path, IZkChildListener listener)// 解除节点变化listener5.2 public void unsubscribeChildChanges(String path, IZkChildListener childListener) 5.3 /**     * parentPath:当前父节点     * 服务端发生如下变化时,会通知客户端     * ---新增子节点     * ---删除子节点     * ---删除子节点     */    public void  listenChildNodeChange(String parentPath){        zkClient.subscribeChildChanges(parentPath, new IZkChildListener(){            public void handleChildChange(String parentPath,                    List<String> currentChilds) throws Exception {                 System.out.println("父节点是 : "+parentPath);                 for(String child:currentChilds){                     System.out.println("子节点路径为-->"+child);                 }            }});    }
  1. IZkStateListener。这个接口主要用在zkClient比较多。参考上面两个即可。

zkClient总结

  1. zkClient极大方便了操作zookeeper,本文只是简单了做了使用说明。具体详细内容需要从源码分析,后续分享出来
原创粉丝点击