zookeeper节点Watch机制实例展示
znode以某种方式发生变化时,“观察”(watch)机制可以让客户端得到通知.可以针对ZooKeeper服务的“操作”来设置观察,该服务的其他 操作可以触发观察.
实现Watcher,复写process方法,处理收到的变更
/**
* Watcher Server,处理收到的变更
* @param watchedEvent
*/
@Override
public void process(WatchedEvent watchedEvent) {
LOG.info("收到事件通知:" + watchedEvent.getState() );
if ( Event.KeeperState.SyncConnected == watchedEvent.getState() ) {
connectedSemaphore.countDown();
}
}
如下实例展示操作节点变化:
public class ZkWatchAPI implements Watcher { public static final Logger LOG = LoggerFactory.getLogger(ZkWatchAPI.class); private static final int SESSION_TIMEOUT = 10000; private ZooKeeper zk = null; private CountDownLatch connectedSemaphore = new CountDownLatch( 1 ); /**
* 连接Zookeeper
* @param connectString Zookeeper服务地址
*/
public void connectionZookeeper(String connectString){
connectionZookeeper(connectString,SESSION_TIMEOUT);
} /**
* <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 );
}
} /**
* <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;
} /**
* <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;
} /**
* <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;
} /**
* <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;
} /**
* <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;
} /**
* <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;
} /**
* Watcher Server,处理收到的变更
* @param watchedEvent
*/
@Override
public void process(WatchedEvent watchedEvent) {
LOG.info("收到事件通知:" + watchedEvent.getState() );
if ( Event.KeeperState.SyncConnected == watchedEvent.getState() ) {
connectedSemaphore.countDown();
}
} /**
* 关闭ZK连接
*/
public void releaseConnection() {
if ( null != zk ) {
try {
this.zk.close();
} catch ( InterruptedException e ) {
LOG.error("release connection error ," + e.getMessage() ,e);
}
}
} public static void main(String [] args){ // 定义父子类节点路径
String rootPath = "/nodeRoot";
String child1Path = rootPath + "/nodeChildren1";
String child2Path = rootPath + "/nodeChildren2"; ZkWatchAPI zkWatchAPI = new ZkWatchAPI(); // 连接zk服务器
zkWatchAPI.connectionZookeeper("192.168.155.47:2181"); // 创建节点数据
if ( zkWatchAPI.createPath( rootPath, "<父>节点数据" ) ) {
System.out.println( "节点[" + rootPath + "]数据内容[" + zkWatchAPI.readData( rootPath ) + "]" );
}
// 创建子节点, 读取 + 删除
if ( zkWatchAPI.createPath( child1Path, "<父-子(1)>节点数据" ) ) {
System.out.println( "节点[" + child1Path + "]数据内容[" + zkWatchAPI.readData( child1Path ) + "]" );
zkWatchAPI.deletePath(child1Path);
System.out.println( "节点[" + child1Path + "]删除值后[" + zkWatchAPI.readData( child1Path ) + "]" );
} // 创建子节点, 读取 + 修改
if ( zkWatchAPI.createPath( child2Path, "<父-子(2)>节点数据" ) ) {
System.out.println( "节点[" + child2Path + "]数据内容[" + zkWatchAPI.readData( child2Path ) + "]" );
zkWatchAPI.writeData( child2Path, "<父-子(2)>节点数据,更新后的数据" );
System.out.println( "节点[" + child2Path+ "]数据内容更新后[" + zkWatchAPI.readData( child2Path ) + "]" );
} // 获取子节点
List<String> childPaths = zkWatchAPI.getChild(rootPath);
if(null != childPaths){
System.out.println( "节点[" + rootPath + "]下的子节点数[" + childPaths.size() + "]" );
for(String childPath : childPaths){
System.out.println(" |--节点名[" + childPath + "]");
}
} // 判断节点是否存在
System.out.println( "检测节点[" + rootPath + "]是否存在:" + zkWatchAPI.isExists(rootPath) );
System.out.println( "检测节点[" + child1Path + "]是否存在:" + zkWatchAPI.isExists(child1Path) );
System.out.println( "检测节点[" + child2Path + "]是否存在:" + zkWatchAPI.isExists(child2Path) ); zkWatchAPI.releaseConnection();
} }
代码运行结果:
[ 74] INFO - rg.apache.zookeeper.ClientCnxn - Socket connection established to 192.168.155.47/192.168.155.47:2181, initiating session
[ 97] INFO - rg.apache.zookeeper.ClientCnxn - Session establishment complete on server 192.168.155.47/192.168.155.47:2181, sessionid = 0x24c11eded7f000b, negotiated timeout = 10000
[ 99] INFO - com.test.zk.ZkWatchAPI - 收到事件通知:SyncConnected
[ 119] INFO - com.test.zk.ZkWatchAPI - 节点创建成功, Path: /nodeRoot, content: <父>节点数据
[ 130] INFO - com.test.zk.ZkWatchAPI - 读取数据成功, path:/nodeRoot, content:<父>节点数据
节点[/nodeRoot]数据内容[<父>节点数据]
[ 140] INFO - com.test.zk.ZkWatchAPI - 节点创建成功, Path: /nodeRoot/nodeChildren1, content: <父-子(1)>节点数据
[ 145] INFO - com.test.zk.ZkWatchAPI - 读取数据成功, path:/nodeRoot/nodeChildren1, content:<父-子(1)>节点数据
节点[/nodeRoot/nodeChildren1]数据内容[<父-子(1)>节点数据]
[ 156] INFO - com.test.zk.ZkWatchAPI - 节点删除成功, Path: /nodeRoot/nodeChildren1
[ 171] ERROR - com.test.zk.ZkWatchAPI - 读取数据失败,发生KeeperException! path: /nodeRoot/nodeChildren1, errMsg:KeeperErrorCode = NoNode for /nodeRoot/nodeChildren1 ...
节点[/nodeRoot/nodeChildren1]删除值后[null]
[ 185] INFO - com.test.zk.ZkWatchAPI - 节点创建成功, Path: /nodeRoot/nodeChildren2, content: <父-子(2)>节点数据
[ 200] INFO - com.test.zk.ZkWatchAPI - 读取数据成功, path:/nodeRoot/nodeChildren2, content:<父-子(2)>节点数据
节点[/nodeRoot/nodeChildren2]数据内容[<父-子(2)>节点数据]
[ 213] INFO - com.test.zk.ZkWatchAPI - 更新数据成功, path:/nodeRoot/nodeChildren2, stat: 21474836549,21474836550,1426235422098,1426235422123,1,0,0,0,43,0,21474836549
[ 228] INFO - com.test.zk.ZkWatchAPI - 读取数据成功, path:/nodeRoot/nodeChildren2, content:<父-子(2)>节点数据,更新后的数据
节点[/nodeRoot/nodeChildren2]数据内容更新后[<父-子(2)>节点数据,更新后的数据]
节点[/nodeRoot]下的子节点数[1]
|--节点名[nodeChildren2]
检测节点[/nodeRoot]是否存在:true
检测节点[/nodeRoot/nodeChildren1]是否存在:false
检测节点[/nodeRoot/nodeChildren2]是否存在:true
[ 319] INFO - rg.apache.zookeeper.ClientCnxn - EventThread shut down
[ 319] INFO - org.apache.zookeeper.ZooKeeper - Session: 0x24c11eded7f000b closed
客户端命令行查看数据:
转载请注明出处:[http://www.cnblogs.com/dennisit/p/4340746.html]
zookeeper节点Watch机制实例展示的更多相关文章
- Zookeeper的Watcher 机制的实现原理
基于 Java API 初探 zookeeper 的使用: 先来简单看一下API的使用: public class ConnectionDemo { public static void main(S ...
- Zookeeper的Watcher机制
ZooKeeper 提供了分布式数据的发布/订阅功能, 在 ZooKeeper 中引入了 Watcher 机制来实现这种分布式的通知功能. ZooKeeper 允许客户端向服务端注册一个 Watche ...
- 品味ZooKeeper之Watcher机制_2
品味ZooKeeper之Watcher机制 本文思维导图如下: 前言 Watcher机制是zookeeper最重要三大特性数据节点Znode+Watcher机制+ACL权限控制中的其中一个,它是zk很 ...
- java 学习笔记(三)ZooKeeper集群搭建实例,以及集成dubbo时的配置 (转)
ZooKeeper集群搭建实例,以及集成dubbo时的配置 zookeeper是什么: Zookeeper,一种分布式应用的协作服务,是Google的Chubby一个开源的实现,是Hadoop的分布式 ...
- 分布式协调组件Zookeeper之 选举机制与ZAB协议
Zookeeper简介: Zookeeper是什么: Zookeeper 是⼀个分布式协调服务的开源框架. 主要⽤来解决分布式集群中应⽤系统的⼀致性问题, 例如怎样避免同时操作同⼀数据造成脏读的问题. ...
- zookeeper acl认证机制及dubbo、kafka集成、zooviewer/idea zk插件配置
ZooKeeper的ACL机制 zookeeper通过ACL机制控制znode节点的访问权限. 首先介绍下znode的5种操作权限:CREATE.READ.WRITE.DELETE.ADMIN 也就是 ...
- Zookeeper的选举机制和同步机制超详细讲解,面试经常问到!
前言 zookeeper相信大家都不陌生,很多分布式中间件都利用zk来提供分布式一致性协调的特性.dubbo官方推荐使用zk作为注册中心,zk也是hadoop和Hbase的重要组件.其他知名的开源中间 ...
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- kafka之zookeeper 节点
1.zookeeper 节点 kafka 在 zookeeper 中的存储结构如下图所示:
随机推荐
- Uploadify 上传文件插件详解
Uploadify 上传文件插件详解 Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中 ...
- mysql innobackupex xtrabackup 大数据量 备份 还原
大数据量备份与还原,始终是个难点.当MYSQL超10G,用mysqldump来导出就比较慢了.在这里推荐xtrabackup,这个工具比mysqldump要快很多. 一.Xtrabackup介绍 1, ...
- MKMapView的使用
#import "ViewController.h" #import "BVAnnotation.h" @interface ViewController () ...
- 10个经典的C语言面试基础算法及代码
10个经典的C语言面试基础算法及代码作者:码农网 – 小峰 原文地址:http://www.codeceo.com/article/10-c-interview-algorithm.html 算法是一 ...
- Android Studio签名打包的两种方式
签名打包的两种方式: 注:给我们自己开发的app签名,就代表着我自己的版权,以后要进行升级,也必须要使用相同的签名才行.签名就代表着自己的身份(即keystore),多个app可以使用同一个签名. 如 ...
- nginx实现访问网站或目录密码认证保护
添加目录登陆认证 location / { auth_basic "提示"; auth_basic_user_file /usr/conf/htpasswd; } auth_bas ...
- 数据库知识整理<三>
保证数据的完整性: 3.1数据完整性概述: 数据完整性的意义:我们知道数据库能防止储存垃圾数据,RDBMS实现该功能主要是通过维护数据完整性来实现的.根据数据完整性实施方法我们将其分为四类:实体完整性 ...
- div+css实现各种形状(精心整理)
1.正方形.div {width: 100px;height: 100px;background: red;} 2.矩形.div {width: 200px;height: 100px;backgro ...
- SVN中Branch的创建与合并
在使用源代码版本控制工具时,最佳实践是一直保持一个主干版本.但是为了应付实际开发中的各种情况,适时的开辟一些分支也是很有必要的.比如在持续开发新功能的同时,需要发布一个新版本,那么就需要从开发主干中建 ...
- Backbone事件管理——Backbone.Events模块API结构
模块Backbone.Events的事件管理是通过Backbone提供的Events API来实现的,该API在1.0版本之前仅仅提供了几个基本的方法,如on.off.trigger.once分别执行 ...