Watcher 在 ZooKeeper 是一个核心功能,Watcher 可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的 Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应.

可以设置观察的操作:exists,getChildren,getData

可以触发观察的操作:create,delete,setData

znode以某种方式发生变化时,“观察”(watch)机制可以让客户端得到通知.可以针对ZooKeeper服务的“操作”来设置观察,该服务的其他 操作可以触发观察.

比如,客户端可以对某个客户端调用exists操作,同时在它上面设置一个观察,如果此时这个znode不存在,则exists返回 false,如果一段时间之后,这个znode被其他客户端创建,则这个观察会被触发,之前的那个客户端就会得到通知.

说明: zookeeper客户端对server的操作都是不可回退的。
意思是说,zk的客户端每次和server进行通信的时候,会记住server上最新的zxid。如果某个时刻,客户端和server断开了连接,那么等到下次重新连接到集群中的机器上时,会检查当前连接上的那个server是否和client有相同的zxid,或者已经是更新的zxid了。一旦客户端发现server的zxid比自己小,那么客户端会断开和这个server的连接,并且重新连接集群中的其它server.

1、链接Zookeeper服务器

/**
* <p>连接Zookeeper</p>
* <pre>
* [关于connectString服务器地址配置]
* 格式: 192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181
* 这个地址配置有多个ip:port之间逗号分隔,底层操作
* ConnectStringParser connectStringParser = new ConnectStringParser(“192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181”);
* 这个类主要就是解析传入地址列表字符串,将其它保存在一个ArrayList中
* ArrayList<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>();
* 接下去,这个地址列表会被进一步封装成StaticHostProvider对象,并且在运行过程中,一直是这个对象来维护整个地址列表。
* ZK客户端将所有Server保存在一个List中,然后随机打乱(这个随机过程是一次性的),并且形成一个环,具体使用的时候,从0号位开始一个一个使用。
* 因此,Server地址能够重复配置,这样能够弥补客户端无法设置Server权重的缺陷,但是也会加大风险。
*
* [客户端和服务端会话说明]
* ZooKeeper中,客户端和服务端建立连接后,会话随之建立,生成一个全局唯一的会话ID(Session ID)。
* 服务器和客户端之间维持的是一个长连接,在SESSION_TIMEOUT时间内,服务器会确定客户端是否正常连接(客户端会定时向服务器发送heart_beat,服务器重置下次SESSION_TIMEOUT时间)。
* 因此,在正常情况下,Session一直有效,并且ZK集群所有机器上都保存这个Session信息。
* 在出现网络或其它问题情况下(例如客户端所连接的那台ZK机器挂了,或是其它原因的网络闪断),客户端与当前连接的那台服务器之间连接断了,
* 这个时候客户端会主动在地址列表(实例化ZK对象的时候传入构造方法的那个参数connectString)中选择新的地址进行连接。
*
* [会话时间]
* 客户端并不是可以随意设置这个会话超时时间,在ZK服务器端对会话超时时间是有限制的,主要是minSessionTimeout和maxSessionTimeout这两个参数设置的。
* 如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。 默认的Session超时时间是在2 * tickTime ~ 20 * tickTime
* </pre>
* @param connectString Zookeeper服务地址
* @param sessionTimeout Zookeeper连接超时时间
*/
public void connectionZookeeper(String connectString, int sessionTimeout){
this.releaseConnection();
try {
// ZK客户端允许我们将ZK服务器的所有地址都配置在这里
zk = new ZooKeeper(connectString, sessionTimeout, this );
// 使用CountDownLatch.await()的线程(当前线程)阻塞直到所有其它拥有CountDownLatch的线程执行完毕(countDown()结果为0)
connectedSemaphore.await();
} catch ( InterruptedException e ) {
LOG.error("连接创建失败,发生 InterruptedException , e " + e.getMessage(), e);
} catch ( IOException e ) {
LOG.error( "连接创建失败,发生 IOException , e " + e.getMessage(), e );
}
}

2、创建节点

    /**
* <p>创建zNode节点, String create(path<节点路径>, data[]<节点内容>, List(ACL访问控制列表), CreateMode<zNode创建类型>) </p><br/>
* <pre>
* 节点创建类型(CreateMode)
* 1、PERSISTENT:持久化节点
* 2、PERSISTENT_SEQUENTIAL:顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
* 3、EPHEMERAL:临时节点客户端,session超时这类节点就会被自动删除
* 4、EPHEMERAL_SEQUENTIAL:临时自动编号节点
* </pre>
* @param path zNode节点路径
* @param data zNode数据内容
* @return 创建成功返回true, 反之返回false.
*/
public boolean createPath( String path, String data ) {
try {
String zkPath = this.zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
LOG.info( "节点创建成功, Path: " + zkPath + ", content: " + data );
return true;
} catch ( KeeperException e ) {
LOG.error( "节点创建失败, 发生KeeperException! path: " + path + ", data:" + data
+ ", errMsg:" + e.getMessage(), e );
} catch ( InterruptedException e ) {
LOG.error( "节点创建失败, 发生 InterruptedException! path: " + path + ", data:" + data
+ ", errMsg:" + e.getMessage(), e );
}
return false;
}

3、删除节点

    /**
* <p>删除一个zMode节点, void delete(path<节点路径>, stat<数据版本号>)</p><br/>
* <pre>
* 说明
* 1、版本号不一致,无法进行数据删除操作.
* 2、如果版本号与znode的版本号不一致,将无法删除,是一种乐观加锁机制;如果将版本号设置为-1,不会去检测版本,直接删除.
* </pre>
* @param path zNode节点路径
* @return 删除成功返回true,反之返回false.
*/
public boolean deletePath( String path ){
try {
this.zk.delete(path,-1);
LOG.info( "节点删除成功, Path: " + path);
return true;
} catch ( KeeperException e ) {
LOG.error( "节点删除失败, 发生KeeperException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
} catch ( InterruptedException e ) {
LOG.error( "节点删除失败, 发生 InterruptedException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
}
return false;
}

4、节点赋值/更新节点

    /**
* <p>更新指定节点数据内容, Stat setData(path<节点路径>, data[]<节点内容>, stat<数据版本号>)</p>
* <pre>
* 设置某个znode上的数据时如果为-1,跳过版本检查
* </pre>
* @param path zNode节点路径
* @param data zNode数据内容
* @return 更新成功返回true,返回返回false
*/
public boolean writeData( String path, String data){
try {
Stat stat = this.zk.setData(path, data.getBytes(), -1);
LOG.info( "更新数据成功, path:" + path + ", stat: " + stat );
return true;
} catch (KeeperException e) {
LOG.error( "更新数据失败, 发生KeeperException! path: " + path + ", data:" + data
+ ", errMsg:" + e.getMessage(), e );
} catch (InterruptedException e) {
LOG.error( "更新数据失败, 发生InterruptedException! path: " + path + ", data:" + data
+ ", errMsg:" + e.getMessage(), e );
}
return false;
}

5、读取节点值

    /**
* <p>读取指定节点数据内容,byte[] getData(path<节点路径>, watcher<监视器>, stat<数据版本号>)</p>
* @param path zNode节点路径
* @return 节点存储的值,有值返回,无值返回null
*/
public String readData( String path ){
String data = null;
try {
data = new String( this.zk.getData( path, false, null ) );
LOG.info( "读取数据成功, path:" + path + ", content:" + data);
} catch (KeeperException e) {
LOG.error( "读取数据失败,发生KeeperException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
} catch (InterruptedException e) {
LOG.error( "读取数据失败,发生InterruptedException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
}
return data;
}

6、判断节点是否存在

    /**
* <p>判断某个zNode节点是否存在, Stat exists(path<节点路径>, watch<并设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper 实例时指定的 watcher>)</p>
* @param path zNode节点路径
* @return 存在返回true,反之返回false
*/
public boolean isExists( String path ){
try {
Stat stat = this.zk.exists( path, false );
return null != stat;
} catch (KeeperException e) {
LOG.error( "读取数据失败,发生KeeperException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
} catch (InterruptedException e) {
LOG.error( "读取数据失败,发生InterruptedException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
}
return false;
}

7、获取某个节点下的子节点

    /**
* <p>获取某个节点下的所有子节点,List getChildren(path<节点路径>, watcher<监视器>)该方法有多个重载</p>
* @param path zNode节点路径
* @return 子节点路径集合 说明,这里返回的值为节点名
* <pre>
* eg.
* /node
* /node/child1
* /node/child2
* getChild( "node" )户的集合中的值为["child1","child2"]
* </pre>
*
*
*
* @throws KeeperException
* @throws InterruptedException
*/
public List<String> getChild( String path ){
try{
List<String> list=this.zk.getChildren( path, false );
if(list.isEmpty()){
LOG.info( "中没有节点" + path );
}
return list;
}catch (KeeperException e) {
LOG.error( "读取子节点数据失败,发生KeeperException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
} catch (InterruptedException e) {
LOG.error( "读取子节点数据失败,发生InterruptedException! path: " + path
+ ", errMsg:" + e.getMessage(), e );
}
return null;
}

8、释放链接

  /**
* 关闭ZK连接
*/
public void releaseConnection() {
if ( null != zk ) {
try {
this.zk.close();
} catch ( InterruptedException e ) {
LOG.error("release connection error ," + e.getMessage() ,e);
}
}
}

转载请注明出处:[http://www.cnblogs.com/dennisit/p/4340688.html]

zookeeper Watcher API 说明的更多相关文章

  1. (原) 2.1 Zookeeper原生API使用

    本文为原创文章,转载请注明出处,谢谢 Zookeeper原生API使用 1.jar包引入,演示版本为3.4.6,非maven项目,可以下载jar包导入到项目中 <dependency> & ...

  2. Zookeeper C API 指南四(C API 概览)(转)

    上一节<Zookeeper C API 指南三(回调函数)>重点讲了 Zookeeper C API 中各种回调函数的原型,本节将切入正题,正式讲解 Zookeeper C API.相信大 ...

  3. Zookeeper C API 指南三(回调函数)(转)

    2013-02-21 12:54 by Haippy, 9237 阅读, 0 评论, 收藏, 编辑 接上一篇<Zookeeper C API 指南二(监视(Wathes), 基本常量和结构体介绍 ...

  4. zookeeper client API实现(python kazoo 的实现)

    这里主要分析zookeeper client API的实现方式,以python kazoo的实现代码为蓝本进行逻辑分析. 一.代码框架及介绍 API分为同步模式和异步模式.同步模式是在异步模式的基础上 ...

  5. 9. 使用ZooKeeper Java API编程

    ZooKeeper是用Java开发的,3.4.6版本的Java API文档可以在http://zookeeper.apache.org/doc/r3.4.6/api/index.html上找到. Ti ...

  6. Zookeeper系列三:Zookeeper客户端的使用(Zookeeper原生API如何进行调用、ZKClient、Curator)和Zookeeper会话

    一.Zookeeper原生API如何进行调用 准备工作: 首先在新建一个maven项目ZK-Demo,然后在pom.xml里面引入zk的依赖 <dependency> <groupI ...

  7. Hadoop生态圈-zookeeper的API用法详解

    Hadoop生态圈-zookeeper的API用法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.测试前准备 1>.开启集群 [yinzhengjie@s101 ~] ...

  8. zookeeper原生API做java客户端

    简介 本文是使用apache提供的原生api做zookeeper客户端 jar包 zookeeper-3.4.5.jar   Demo package bjsxt.zookeeper.base; im ...

  9. Zookeeper JAVA API的使用

    0. 前言 zookeeper安装及使用  http://www.cnblogs.com/rocky-fang/p/7880309.html 1. 开发环境配置 1.1 idea创建一个maven工程 ...

随机推荐

  1. VO,DO,DTO,PO,POJO,EJB

    PO:persistent Object,持久化对象,和数据库一一对应. VO:view Object,视图对象,用于展示,把某个页面或者组件的数据封装起来. DO:Domain Object,领域对 ...

  2. 获得select下拉框的值

    html -------------------------------------------------------------------------------------- <sele ...

  3. 使用代码在windows-store中打开、搜索应用程序

    //Launcher.LaunchUriAsync(newUri("ms-windows-store:PDP?PFN=" + Package.Current.Id.FamilyNa ...

  4. 怎么定义 logger

    随便打开一个 spring 的 源文件,比如  PathMatchingResourcePatternResolver.class 里面是这样定义logger 的 import org.apache. ...

  5. WordPaster-Chrome浏览器控件安装方法

    将WordPaster.crx拖到Chrome扩展面板中安装

  6. React与ES6(一)开篇介绍

    React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...

  7. 大数据处理对象CLOG BLOG

    File 文件类的使用 decimal 类型(规范小数的形式)  longtext 类型(存储字符大数据) 存入文本文件到数据库 InputStream FileInputStream CLOG 类的 ...

  8. iOS 开发者必知的 75 个工具(译文)

    原文地址:http://benscheirman.com/2013/08/the-ios-developers-toolbelt (需FQ)   如果你去到一位熟练的木匠的工作室,你总是能发现他/她有 ...

  9. JS DOM操作

    一.DOM基础 1.节点(node)层次 Document--最顶层的节点,所有的其他节点都是附属于它的. DocumentType--DTD引用(使用<!DOCTYPE>语法)的对象表现 ...

  10. Asp.Net Web API 2第十八课——Working with Entity Relations in OData

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html. 本文的示例代码的下载地址 ...