ZooKeeper与Curator注册和监控
Curator提供了对zookeeper客户端的封装,并监控连接状态和会话session,特别是会话session过期后,curator能够重新连接zookeeper,并且创建一个新的session。
对于zk的使用者来说,session的概念至关重要,如果想了解更多session的说明,请访问:http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
zk客户端和zk服务器间主要可能存在下面几种异常情况:
1. 短暂失去连接:此时客户端检测到与服务端的连接已经断开,但是服务端维护的客户端session尚未过期,之后客户端和服务端重新建立了连接;当客户端重新连接后,由于session没有过期,zookeeper能够保证连接恢复后保持正常服务。
2. 失去连接时间很长:此时服务器相对于客户端的session已经过期了,与先前session相关的watcher和ephemeral的路径和数据都会消失;当Curator重新创建了与zk的连接后,会获取到session expired异常,Curator会销毁先前的session,并且会创建一个新的session,需要注意的是,与之前session相关的watcher和ephemeral类型的路径和数据在新的session中也不会存在,需要开发者在CuratorFramework.getConnectionStateListenable().addListener()中添加状态监听事件,对ConnectionState.LOST事件进行监听,当session过期后,使得之前的session状态得以恢复。对于ephemeral类型,在客户端应该保持数据的状态,以便及时恢复。
3. 客户端重新启动:不论先前的zk session是否已经过期,都需要重新创建临时节点、添加数据和watch事件,先前的session也会在稍后的一段时间内过期。
4. Zk服务器重新启动:由于zk将session信息存放到了硬盘上,因此重启后,先前未过期的session仍然存在,在zk服务器启动后,客户端与zk服务器创建新的连接,并使用先前的session,与1相同。
5. 需要注意的是,当session过期了,在session过期期间另外的客户端修改了zk的值,那么这个修改在客户端重新连接到zk上时,zk客户端不会接收到这个修改的watch事件(尽管添加了watch),如果需要严格的watch逻辑,就需要在curator的状态监控中添加逻辑。
特别提示:watcher仅仅是一次性的,zookeeper通知了watcher事件后,就会将这个watcher从session中删除,因此,如果想继续监控,就要添加新的watcher。
下面提供了对persistent和ephemeral两种类型节点的监控方法,其中get方法说明了persistent节点如何监控,而register方法说明了ephemeral类型的节点如何监控。
public class CuratorTest {
private CuratorFramework zkTools;
private ConcurrentSkipListSet watchers = newConcurrentSkipListSet();
private static Charset charset = Charset.forName("utf-8");
public CuratorTest() {
zkTools = CuratorFrameworkFactory
.builder()
.connectString("10.11.21.78:12306")
.namespace("zk/test")
.retryPolicy(new RetryNTimes(2000,20000))
.build();
zkTools.start();
}
public void addReconnectionWatcher(final String path,final ZookeeperWatcherType watcherType,final CuratorWatcher watcher){
synchronized (this) {
if(!watchers.contains(watcher.toString()))//不要添加重复的监听事件
{
watchers.add(watcher.toString());
System.out.println("add new watcher " + watcher);
zkTools.getConnectionStateListenable().addListener(newConnectionStateListener() {
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
System.out.println(newState);
if(newState == ConnectionState.LOST){//处理session过期
try{
if(watcherType == ZookeeperWatcherType.EXITS){
zkTools.checkExists().usingWatcher(watcher).forPath(path);
}else if(watcherType == ZookeeperWatcherType.GET_CHILDREN){
zkTools.getChildren().usingWatcher(watcher).forPath(path);
}else if(watcherType == ZookeeperWatcherType.GET_DATA){
zkTools.getData().usingWatcher(watcher).forPath(path);
}else if(watcherType == ZookeeperWatcherType.CREATE_ON_NO_EXITS){
//ephemeral类型的节点session过期了,需要重新创建节点,并且注册监听事件,之后监听事件中,
//会处理create事件,将路径值恢复到先前状态
Stat stat =zkTools.checkExists().usingWatcher(watcher).forPath(path);
if(stat == null){
System.err.println("to create");
zkTools.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(path);
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
}
}
public void create() throws Exception{
zkTools.create()//创建一个路径
.creatingParentsIfNeeded()//如果指定的节点的父节点不存在,递归创建父节点
.withMode(CreateMode.PERSISTENT)//存储类型(临时的还是持久的)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)//访问权限
.forPath("zk/test");//创建的路径
}
public void put() throws Exception{
zkTools.//对路径节点赋值
setData().
forPath("zk/test","hello world".getBytes(Charset.forName("utf-8")));
}
public void get() throws Exception{
String path = "zk/test";
ZKWatch watch = new ZKWatch(path);
byte[] buffer = zkTools.
getData().
usingWatcher(watch).forPath(path);
System.out.println(new String(buffer,charset));
//添加session过期的监控
addReconnectionWatcher(path, ZookeeperWatcherType.GET_DATA, watch);
}
public void register() throws Exception{
String ip = InetAddress.getLocalHost().getHostAddress();
String registeNode = "zk/register/"+ip;//节点路径
byte[] data = "disable".getBytes(charset);//节点值
CuratorWatcher watcher = new ZKWatchRegister(registeNode,data); //创建一个register watcher
Stat stat = zkTools.checkExists().forPath(registeNode);
if(stat != null){
zkTools.delete().forPath(registeNode);
}
zkTools.create()
.creatingParentsIfNeeded() .withMode(CreateMode.EPHEMERAL)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(registeNode,data);//创建的路径和值
//添加到session过期监控事件中
addReconnectionWatcher(registeNode, ZookeeperWatcherType.CREATE_ON_NO_EXITS,watcher);
data = zkTools.getData().usingWatcher(watcher).forPath(registeNode);
System.out.println("get path form zk : "+registeNode+":"+new String(data,charset));
}
public static void main(String[] args) throws Exception {
CuratorTest test = new CuratorTest();
test.get();
test.register();
Thread.sleep(10000000000L);
}
public class ZKWatch implements CuratorWatcher{
private final String path;
public String getPath() {
return path;
}
public ZKWatch(String path) {
this.path = path;
}
@Override
public void process(WatchedEvent event) throws Exception {
System.out.println(event.getType());
if(event.getType() == EventType.NodeDataChanged){
byte[] data = zkTools.
getData().
usingWatcher(this).forPath(path);
System.out.println(path+":"+new String(data,Charset.forName("utf-8")));
}
}
}
public class ZKWatchRegister implements CuratorWatcher{
private final String path;
private byte[] value;
public String getPath() {
return path;
}
public ZKWatchRegister(String path,byte[] value) {
this.path = path;
this.value = value;
}
@Override
public void process(WatchedEvent event) throws Exception {
System.out.println(event.getType());
if(event.getType() == EventType.NodeDataChanged){
//节点数据改变了,需要记录下来,以便session过期后,能够恢复到先前的数据状态
byte[] data = zkTools.
getData().
usingWatcher(this).forPath(path);
value = data;
System.out.println(path+":"+new String(data,charset));
}else if(event.getType() == EventType.NodeDeleted){
//节点被删除了,需要创建新的节点
System.out.println(path + ":" + path +" has been deleted.");
Stat stat = zkTools.checkExists().usingWatcher(this).forPath(path);
if(stat == null){
zkTools.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(path);
}
}else if(event.getType() == EventType.NodeCreated){
//节点被创建时,需要添加监听事件(创建可能是由于session过期后,curator的状态监听部分触发的)
System.out.println(path + ":" +" has been created!" + "the current data is " +new String(value));
zkTools.setData().forPath(path, value);
zkTools.getData().usingWatcher(this).forPath(path);
}
}
}
public enum ZookeeperWatcherType{
GET_DATA,GET_CHILDREN,EXITS,CREATE_ON_NO_EXITS
}
}
ZooKeeper与Curator注册和监控的更多相关文章
- Zookeeper客户端Curator使用详解
Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...
- Zookeeper实现分布式集群监控
Zookeeepr实现分布式集群监控 Zookeeper中节点有两种:临时节点和永久节点 从类型上看节点又可以分为四种节点类型:PERSIST,PERSIST_SEQUENTIAL,EPHEMERAL ...
- zookeeper(六):Zookeeper客户端Curator的API使用详解
简介 Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连.反复注册Watcher和NodeExistsEx ...
- 转:Zookeeper客户端Curator使用详解
原文:https://www.jianshu.com/p/70151fc0ef5d Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBo ...
- 【转帖】基于Zookeeper的服务注册与发现
http://www.techweb.com.cn/network/hardware/2015-12-25/2246973.shtml 背景 大多数系统都是从一个单一系统开始起步的,随着公司业务的快速 ...
- ZeroMQ接口函数之 :zmq_socket_monitor - 注册一个监控回调函数
ZeroMQ 官方地址 :http://api.zeromq.org/4-2:zmq-socket-monitor zmq_socket_monitor(3) ØMQ Manual - ØMQ/4.1 ...
- Web Api 基于Zookeeper的服务注册与发现
安装与差异 Zookeeper安装请参考我上篇文章 http://www.cnblogs.com/woxpp/p/7700368.html 基于Nginx的服务提供和消费 基于zookeeper的服务 ...
- 网站集群架构(LVS负载均衡、Nginx代理缓存、Nginx动静分离、Rsync+Inotify全网备份、Zabbix自动注册全网监控)--技术流ken
前言 最近做了一个不大不小的项目,现就删繁就简单独拿出来web集群这一块写一篇博客.数据库集群请参考<MySQL集群架构篇:MHA+MySQL-PROXY+LVS实现MySQL集群架构高可用/高 ...
- window7环境下ZooKeeper的安装运行及监控查看
原文:http://www.cnblogs.com/RainAndWind/p/4668427.html ZooKeeper是一个分布式开源框架,供了协调分布式应用的基本服务.这些天在使用DUBBO, ...
随机推荐
- 创建Fragment
你可以认为fragment是Activity中模块化的部分.Fragment有它自己的生命周期,接收它自己的输入事件,并且你可以在Activity运行的时候添加或移除它(有点像可以被重用在不同Acti ...
- [游戏学习24] MFC 各种绘图 字体学习
>_<:这里包含字体设置及各种绘图,只要稍微看一下代码就能理解,这里不多介绍 >_<:Hello.h #include<afxwin.h> class CMyApp ...
- 使用ConditionalScope进行高效的SharePoint CSOM编程
在上一篇文章中讲述了 ExceptionHandlingScope的使用后,本章主要讲述ConditionalScope的用法. ConditionalScope在设计思路和解决问题上同Excepti ...
- C++ 顺序容器
<C++ Primer 4th>读书笔记 顺序容器内的元素按其位置存储和访问.容器类共享公共的接口,每种容器类型提供一组不同的时间和功能折衷方案.通常不需要修改代码,只需改变类型声明,用一 ...
- [读书笔记]C#学习笔记四: C#2.0泛型 可控类型 匿名方法和迭代器
前言 C#1.0的委托特性使方法作为其他方法的参数来传递,而C#2.0 中提出的泛型特性则使类型可以被参数化,从而不必再为不同的类型提供特殊版本的实现方法.另外C#2.0还提出了可空类型,匿名方法和迭 ...
- paip.提升性能---string split
paip.提升性能---string split 大概一万次就能看到慢的兰.. /////split 慢的原因.因为使用了正则表达式的,这样,就慢的了.. 作者Attilax 艾龙, EMAIL: ...
- android: open failed: EACCES (Permission denied)
1. 问题描述:在Android中,用程序访问Sdcard时,有时出现“java.io.IOException: open failed: EACCES (Permission denied)&qu ...
- ASP.NET Web API中的参数绑定总结
ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...
- DRAM 内存介绍(二)
参考资料:http://www.anandtech.com/show/3851/everything-you-always-wanted-to-know-about-sdram-memory-but- ...
- POI 设置EXCEL单元格格式(日期数字文本等)
HSSFCellStyle style0 = workbook2003.createCellStyle(); style0.setBorderBottom(HSSFCellStyle.BORDER_T ...