Zookeeper Client简介
直接使用zk的api实现业务功能比较繁琐。因为要处理session loss,session expire等异常,在发生这些异常后进行重连。又因为ZK的watcher是一次性的,如果要基于wather实现发布/订阅模式,还要自己包装一下,将一次性订阅包装成持久订阅。另外如果要使用抽象级别更高的功能,比如分布式锁,leader选举等,还要自己额外做很多事情。这里介绍下ZK的两个第三方客户端包装小工具,可以分别解决上述小问题。
一、 zkClient
zkClient主要做了两件事情。一件是在session loss和session expire时自动创建新的ZooKeeper实例进行重连。另一件是将一次性watcher包装为持久watcher。后者的具体做法是简单的在watcher回调中,重新读取数据的同时再注册相同的watcher实例。
zkClient简单的使用样例如下:
public static void testzkClient(final String serverList) {ZkClient zkClient4subChild = new ZkClient(serverList);zkClient4subChild.subscribeChildChanges(PATH, new IZkChildListener() {@Overridepublic void handleChildChange(String parentPath, List currentChilds) throws Exception {System.out.println(prefix() + "clildren of path " + parentPath + ":" + currentChilds);}});
上面是订阅children变化,下面是订阅数据变化
ZkClient zkClient4subData = new ZkClient(serverList);zkClient4subData.subscribeDataChanges(PATH, new IZkDataListener() {@Overridepublic void handleDataChange(String dataPath, Object data) throws Exception {System.out.println(prefix() + "Data of " + dataPath + " has changed");}@Overridepublic void handleDataDeleted(String dataPath) throws Exception {System.out.println(prefix() + dataPath + " has deleted");}});
订阅连接状态的变化:
ZkClient zkClient4subStat = new ZkClient(serverList);zkClient4subStat.subscribeStateChanges(new IZkStateListener() {@Overridepublic void handleNewSession() throws Exception {System.out.println(prefix() + "handleNewSession()");}@Overridepublic void handleStateChanged(KeeperState stat) throws Exception {System.out.println(prefix() + "handleStateChanged,stat:" + stat);}});
下面表格列出了写操作与ZK内部产生的事件的对应关系:
**event For "/path"** | **event For "/path/child"** | |
---|---|---|
**create("/path")** | EventType.NodeCreated | NA |
**delete("/path")** | EventType.NodeDeleted | NA |
**setData("/path")** | EventType.NodeDataChanged | NA |
**create("/path/child")** | EventType.NodeChildrenChanged | EventType.NodeCreated |
**delete("/path/child")** | EventType.NodeChildrenChanged | EventType.NodeDeleted |
**setData("/path/child")** | NA | EventType.NodeDataChanged |
而ZK内部的写事件与所触发的watcher的对应关系如下:
**event For "/path"** | **defaultWatcher** | **exists ("/path")** | **getData ("/path")** | **getChildren ("/path")** |
---|---|---|---|---|
**EventType.None** | √ | √ | √ | √ |
**EventType.NodeCreated** | √ | √ | ||
**EventType.NodeDeleted** | √(不正常) | √ | ||
**EventType.NodeDataChanged** | √ | √ | ||
**EventType.NodeChildrenChanged** | √ |
综合上面两个表,我们可以总结出各种写操作可以触发哪些watcher,如下表所示:
**"/path"** | **"/path/child"** | |||||
---|---|---|---|---|---|---|
**exists** | **getData** | **getChildren** | **exists** | **getData** | **getChildren** | |
**create("/path")** | **√** | **√** | ** ** | ** ** | ** ** | ** ** |
**delete("/path")** | **√** | **√** | **√** | ** ** | ** ** | ** ** |
**setData("/path")** | **√** | **√** | ** ** | ** ** | ** ** | ** ** |
**create("/path/child")** | ** ** | ** ** | **√** | **√** | **√** | ** ** |
**delete("/path/child")** | ** ** | ** ** | **√** | **√** | **√** | **√** |
**setData("/path/child")** | ** ** | ** ** | ** ** | **√** | **√** | ** ** |
如果发生session close、authFail和invalid,那么所有类型的wather都会被触发 zkClient除了做了一些便捷包装之外,对watcher使用做了一点增强。比如subscribeChildChanges实际上是通过exists和getChildren关注了两个事件。这样当create("/path")时,对应path上通过getChildren注册的listener也会被调用。另外subscribeDataChanges实际上只是通过exists注册了事件。因为从上表可以看到,对于一个更新,通过exists和getData注册的watcher要么都会触发,要么都不会触发。 zkClient地址:[https://github.com/sgroschupf/zkclient](https://github.com/sgroschupf/zkclient) Maven工程中使用zkClient需要加的依赖:
<dependency><groupId>zkclient</groupId><artifactId>zkclient</artifactId><version>0.1</version></dependency>
二、 menagerie
menagerie基于Zookeeper实现了java.util.concurrent包的一个分布式版本。这个封装是更大粒度上对各种分布式一致性使用场景的抽象。其中最基础和常用的是一个分布式锁的实现:
org.menagerie.locks.ReentrantZkLock,通过ZooKeeper的全局有序的特性和EPHEMERAL_SEQUENTIAL类型znode的支持,实现了分布式锁。具体做法是:不同的client上每个试图获得锁的线程,都在相同的basepath下面创建一个EPHEMERAL_SEQUENTIAL的node。EPHEMERAL表示要创建的是临时znode,创建连接断开时会自动删除; SEQUENTIAL表示要自动在传入的path后面缀上一个自增的全局唯一后缀,作为最终的path。因此对不同的请求ZK会生成不同的后缀,并分别返回带了各自后缀的path给各个请求。因为ZK全局有序的特性,不管client请求怎样先后到达,在ZKServer端都会最终排好一个顺序,因此自增后缀最小的那个子节点,就对应第一个到达ZK的有效请求。然后client读取basepath下的所有子节点和ZK返回给自己的path进行比较,当发现自己创建的sequential node的后缀序号排在第一个时,就认为自己获得了锁;否则的话,就认为自己没有获得锁。这时肯定是有其他并发的并且是没有断开的client/线程先创建了node。
基于分布式锁,还实现了其他业务场景,比如leader选举:
public static void leaderElectionTest() { ZkSessionManager zksm = new DefaultZkSessionManager(“ZK-host-ip:2181”, 5000); LeaderElector elector = new ZkLeaderElector(“/leaderElectionTest”, zksm, Ids.OPEN_ACL_UNSAFE); if (elector.nominateSelfForLeader()) { System.out.println(“Try to become the leader success!”); } }
java.util.concurrent包下面的其他接口实现,也主要是基于ReentrantZkLock的,比如ZkHashMap实现了ConcurrentMap。具体请参见menagerie的API文档
menagerie地址:https://github.com/wxuedong/menagerie
Maven工程中使用menagerie需要加的依赖:
<dependency><groupId>org.menagerie</groupId><artifactId>menagerie</artifactId><version>1.1-SNAPSHOT</version></dependency>
Zookeeper Client简介相关推荐
- zookeeper使用简介及注意事项
一.zookeeper使用简介 场景一 有这样一个场景:系统中有大约100w的用户,每个用户平均有3个邮箱账号,每隔5分钟,每个邮箱账需要收取100封邮件,最多3亿份邮件需要下载到服务器中(不含附件和 ...
- Zookeeper的简介及命令行操作
目录 前言 1.Zookeeper简介 2.Zookeeper结构 3.Zookeeper常用的命令行操作 总结: 目录 前言 作为一款第三方的协调服务框架,ZK被应用在许多地方,如:Hbase中用于 ...
- Zookeeper(一)——简介
Zookeeper简介 Zookeeper 是一个 开源的.分布式的.为分布式框架提供协调服务的Apache项目,是一个基于观察者模式的分布式服务管理框架,负责存储和管理重要数据,接受观察者的注册.一 ...
- Zookeeper基础简介
基础信息 zookeeper的每个节点,既可以存储自身的数据,又可以扩展子节点.Zookeeper本身不提供序列化支持,我们可以使用Protobuf或者Thrift等协议把数据序列化处理. Zooke ...
- 【Zookeeper学习】Apache Zookeeper项目简介
正在撰写,稍后来访-- 转载于:https://www.cnblogs.com/zhangningbo/p/4107373.html
- [转载] zookeeper 分布式锁服务
转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...
- zookeeper 分布式锁服务
分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那一层来挡.当大量的行锁.表锁.事务充斥着数据库的时候.一般web应用很多的瓶颈都在数据库上,这里给大家介绍的是减轻数据库锁负担的一种 ...
- [转载]Zookeeper开源客户端框架Curator简介
转载声明:http://macrochen.iteye.com/blog/1366136 Zookeeper开源客户端框架Curator简介 博客分类: Distributed Open Source ...
- zookeeper快速入门——简介
在几十年前,一个独立的计算机上往往部署着一套完整的应用系统.当时因为网络稳定性及速度的限制,将相关联的服务部署在一台机器上,让它们使用系统机制通信--比如管道,文件等,往往是最稳定和最高效的.然而随着 ...
最新文章
- 王者荣耀10连胜,竟然也有人不相信,猎游大神带菜鸡玩家10连胜
- 第二章 选择符和属性
- 软件测试技术 homework2
- android静态类保存context,Android:静态获取Context是一个好习惯吗?
- computed的原理
- 安装 Visual Studio Async CTP
- 数据之路 - Python爬虫 - Scrapy框架
- 游戏中植入广告的例子
- 无盘服务器怎么安装驱动,无盘网吧的摄像头驱动安装的解决方案
- 阻止switch开关的事件冒泡
- 程序人生丨25岁毕业,月薪1万
- Java实现蓝桥杯勇者斗恶龙
- 三分法与二分法的区别和三分法总结
- 深信服2020校招前端一面面经
- 二本网络工程学生转型大数据开发,放弃京东offer,选择了二线城市
- 首个比较研究表明维持期强柱患者减量续用TNFi疗效尚佳且药费省
- winform模拟登陆网页_用c#模拟手机app向网站登录,如何写?
- 关键词挖掘在网站SEO中的重要性
- Java 官网下载+安装(Linux)
- 风格迁移相关论文阅读笔记
热门文章
- 数据库mysql的注释怎么加_mysql表如何添加字段注释
- lisp语言cond和if套用_AutoCAD LISP 循环选择语句cond
- matlab中用于离散系统求解的命令,MATLAB求解规划问题(线性规划, 整数规划, 非线性规划)...
- mysql 截取最后三位查询
- 计算机专业英语第五章ppt,计算机专业英语课件5.ppt
- oracle的exp程序,数据库expimp迁移的整个过程,及注意事项
- python单词统计、给定一个段落()_自己动手Python写一个词频统计小项目
- linux 22 口令自动传马,近期用到的linux命令
- python爬取flash数据_爬取flash数据
- mdb新版本打不开_救命!!! 我打不开她给我的Pr工程……