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() {
@Override
public 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() {
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println(prefix() + "Data of " + dataPath + " has changed");
} @Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println(prefix() + dataPath + " has deleted");
}
});
订阅连接状态的变化:
ZkClient zkClient4subStat = new ZkClient(serverList);
zkClient4subStat.subscribeStateChanges(new IZkStateListener() {
@Override
public void handleNewSession() throws Exception {
System.out.println(prefix() + "handleNewSession()");
} @Override
public 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系列4:ZooKeeper API简介及编程
问题导读: 1.ZooKeeper API 共包含几个包? 2.如何使用ZooKeeper API 创建zookeeper应用程序? 1)ZooKeeper API 简介 ZooKeeper AP ...
- zookeeper client API实现(python kazoo 的实现)
这里主要分析zookeeper client API的实现方式,以python kazoo的实现代码为蓝本进行逻辑分析. 一.代码框架及介绍 API分为同步模式和异步模式.同步模式是在异步模式的基础上 ...
- elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)
一.ES Client 简介 1. ES是一个服务,采用C/S结构 2. 回顾 ES的架构 3. ES支持的客户端连接方式 3.1 REST API ,端口 9200 这种连接方式对应于架构图中的RE ...
- Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)
elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介.Java REST Client.Java Client.Spri ...
- zookeeper的简介和相关命令操作
.personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...
- [Zookeeper研究]一 Zookeeper技术简介
最近的项目中使用到了Zookeeper.Kafka以及Storm.仔细研究了一下,觉得这几个开源项目对于搞分布式的人来说是非常有用的,所以想把自己的一点心得体会总结一下,希望能对大家有所帮助. 首先从 ...
- Zookeeper Client基础操作和Java调用
## Zookeeper > Zookeeper目前用来做数据同步,再各个服务之前同步关键信息 i.客户端操作 1. 创建 create [-s] [-e] path data acl -s 为 ...
- Java学习之ZooKeeper瑞士军刀简介
1.简介 ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现.分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅.负载均衡.命名服务 ...
- 服务端相关知识学习(六)Zookeeper client
Zookeeper的client是通过Zookeeper类提供的.前面曾经说过,Zookeeper给使用者提供的是一个类似操作系统的文件结构,只不过这个结构是分布式的.可以理解为一个分布式的文件系统. ...
随机推荐
- Eclipse搭建SSH框架(Struts2+Spring+Hibernate)
见识少的我经过一天多的研究才知道,在MyEclipse中搭好的框架的配置文件和jar包是通用的.接下来——亮剑! 工具:Eclipse+Tomcat+Mysql 一.先在Eclipse中配置好Tomc ...
- REdis MASTER aborted replication NOAUTH Authentication required
对于REdis集群,如果设置了requirepass,则一定要设置masterauth,否则从节点无法正常工作,查看从节点日志可以看到哪下内容:19213:S 22 Apr 2019 10:52:17 ...
- JSON.parse()——Uncaught SyntaxError: Unexpected token \ in JSON at position 1
背景:项目安全处理方面之一 ——对特殊字符进行编解码(后端编码,前端解码) 特殊字符: " %22 \ %5C / %2F & %26 % %25 ' ...
- cisco基本配置命令
实验命令 router> enable 从用户模式进入特权模式 router# disable or exit 从特权模式退出到用户模式 router# show sessions 查看本机上的 ...
- 学习Python第七天
进制拾遗: 二进制:01 八进制:01234567 十进制:0123456789 十六进制:0123456789ABCDEF 十进制转换八,十六进制语法 oct()八进制 关于8进制是逢8进一位的,我 ...
- IDEA安装插件提示was not installed: Cannot download解决办法
打开settings->system settings->updata,把下面的Use secure Connetion去掉
- Promise实践
一.概念 Promise是异步编程的解决方案之一,与事件驱动+回调函数并列. Promise是专门为异步编程设计的封闭的一次性用品,封闭体现在只有异步操作的结果能改变其状态,其他任何操作都不能改变其状 ...
- Android-Java-接口Interface
接口Interface 与 抽象类不同: 抽象类关注的是事物本质,例如:水果Fruit 属于抽象的,说去买水果 是模糊的概念 是抽象的概念 不具体,到底买什么水果不知道,而水果包含了 香蕉,橘子 很多 ...
- 背水一战 Windows 10 (94) - 选取器: 自定义文件打开选取器
[源码下载] 背水一战 Windows 10 (94) - 选取器: 自定义文件打开选取器 作者:webabcd 介绍背水一战 Windows 10 之 选取器 自定义文件打开选取器 示例1.演示如何 ...
- Chrome部分站点无法启用Flash问题
## 69.0之前 ## 1. 打开 chrome://settings/content/flash 2. 禁止网站运行Flash -> 改为“先询问(推荐)” 3. 允许->添加 4. ...