zookeeper项目使用几点小结
背景
前段时间学习了zookeeper后,在新的项目中刚好派上了用场,我在项目中主要负责分布式任务调度模块的开发,对我自己来说是个不小的挑战。
分布式的任务调度,技术上我们选择了zookeeper,具体的整个分布式任务调度的架构选择会另起一篇文章进行介绍。
本文主要是介绍自己在项目中zookeeper的一些扩展使用,希望可以对大家有所帮助。
项目中使用的zookeeper版本3.3.3,对应的文档地址: http://zookeeper.apache.org/doc/trunk/
扩展一:优先集群
先来点背景知识:
1.zookeeper中的server机器之间会组成leader/follower集群,1:n的关系。采用了paxos一致性算法保证了数据的一致性,就是leader/follower会采用通讯的方式进行投票来实现paxns。
2.zookeeper还支持一种observer模式,提供只读服务不参与投票,提升系统,对应文档: http://zookeeper.apache.org/doc/trunk/zookeeperObservers.html
我们项目特性的决定了我们需要进行跨机房操作,比如杭州,美国,香港,青岛等多个机房之间进行数据交互。
跨机房之间对应的网络延迟都比较大,比如中美机房走海底光缆有ping操作200ms的延迟,杭州和青岛机房有70ms的延迟。
为了提升系统的网络性能,我们在部署zookeeper网络时会在每个机房部署节点,多个机房之间再组成一个大的网络保证数据一致性。(zookeeper千万别再搞多个集群)
最后的部署结构就会是:
- 杭州机房 >=3台 (构建leader/follower的zk集群)
- 青岛机房 >=1台 (构建observer的zk集群)
- 美国机房 >=1台 (构建observer的zk集群)
- 香港机房 >=1台 (构建observer的zk集群)

- 先使用美国机房的集群ip初始化一次zk client
- 通过反射方式,强制在初始化后的zk client中的server列表中又加入杭州机房的机器列表
1.ZooKeeper zk = null;
2. try {
3. zk = new ZooKeeper(cluster1, sessionTimeout, new AsyncWatcher() {
4.
5. public void asyncProcess(WatchedEvent event) {
6. //do nothing
7. }
8.
9. });
10. if (serveraddrs.size() > 1) {
11. // 强制的声明accessible
12. ReflectionUtils.makeAccessible(clientCnxnField);
13. ReflectionUtils.makeAccessible(serverAddrsField);
14. // 添加第二组集群列表
15. for (int i = 1; i < serveraddrs.size(); i++) {
16. String cluster = serveraddrs.get(i);
17. // 强制获取zk中的地址信息
18. ClientCnxn cnxn = (ClientCnxn) ReflectionUtils.getField(clientCnxnField, zk);
19. List<InetSocketAddress> serverAddrs = (List<InetSocketAddress>) ReflectionUtils
20. .getField(serverAddrsField, cnxn);
21. // 添加第二组集群列表
22. serverAddrs.addAll(buildServerAddrs(cluster));
23. }
24. }
25. }
扩展二:异步Watcher处理
最早在看zookeeper的代码时,一直对它的watcher处理比较满意,使用watcher推送数据可以很方便的实现分布式锁的功能。
zookeeper的watcher实现原理也挺简单的,就是在zookeeper client和zookeeper server上都保存一份对应的watcher对象。每个zookeeper机器都会有一份完整的node tree数据和watcher数据,每次leader通知follower/observer数据发生变更后,每个zookeeper server会根据自己节点中的watcher事件推送给响应的zookeeper client,每个zk client收到后再根据内存中的watcher引用,进行回调。
这里会有个问题,就是zk client在处理watcher时,回凋的过程是一个串行的执行过程,所以单个watcher的处理慢会影响整个列表的响应。
可以看一下ClientCnxn类中的EventThread处理,该线程会定时消费一个queue的数据,挨个调用processEvent(Object event) 进行回调处理。
扩展代码:
1.public abstract class AsyncWatcher implements Watcher {
2.
3. private static final int DEFAULT_POOL_SIZE = 30;
4. private static final int DEFAULT_ACCEPT_COUNT = 60;
5.
6. private static ExecutorService executor = new ThreadPoolExecutor(
7. 1,
8. DEFAULT_POOL_SIZE,
9. 0L,
10. TimeUnit.MILLISECONDS,
11. new ArrayBlockingQueue(
12. DEFAULT_ACCEPT_COUNT),
13. new NamedThreadFactory(
14. "Arbitrate-Async-Watcher"),
15. new ThreadPoolExecutor.CallerRunsPolicy());
16.
17. public void process(final WatchedEvent event) {
18. executor.execute(new Runnable() {//提交异步处理
19.
20. @Override
21. public void run() {
22. asyncProcess(event);
23. }
24. });
25.
26. }
27.
28. public abstract void asyncProcess(WatchedEvent event);
29.
30.}
- zookeeper针对watcher的调用是以单线程串行的方式进行处理,容易造成堵塞影响,monitor的数据同步及时性
- AsyncWatcher为采取的一种策略为当不超过acceptCount=60的任务时,会采用异步线程的方式处理。如果超过60任务,会变为原先的单线程串行的模式
扩展三:重试处理
这个也不多说啥,看一下相关文档就清楚了
- http://wiki.apache.org/hadoop/ZooKeeper/ErrorHandling
- http://wiki.apache.org/hadoop/ZooKeeper/FAQ#A3
1.public interface ZooKeeperOperation<T> {
2.
3. public T execute() throws KeeperException, InterruptedException;
4.}
5.
6.
7./**
8. * 包装重试策略
9. */
10. public <T> T retryOperation(ZooKeeperOperation<T> operation) throws KeeperException,
11. InterruptedException {
12. KeeperException exception = null;
13. for (int i = 0; i < maxRetry; i++) {
14. try {
15. return (T) operation.execute();
16. } catch (KeeperException.SessionExpiredException e) {
17. logger.warn("Session expired for: " + this + " so reconnecting due to: " + e, e);
18. throw e;
19. } catch (KeeperException.ConnectionLossException e) { //特殊处理Connection Loss
20. if (exception == null) {
21. exception = e;
22. }
23. logger.warn("Attempt " + i + " failed with connection loss so "
24. + "attempting to reconnect: " + e, e);
25.
26. retryDelay(i);
27. }
28. }
29.
30. throw exception;
31. }
注意点:Watcher原子性
在使用zookeeper的过程中,需要特别注意一点就是注册对应watcher事件时,如果当前的节点已经满足了条件,比如exist的watcher,它不会触发你的watcher,而会等待下一次watcher条件的满足。
它的watcher是一个一次性的监听,而不是一个永久的订阅过程。所以在watcher响应和再次注册watcher过程并不是一个原子操作,编写多线程代码和锁时需要特别注意
总结
zookeepr是一个挺不错的产品,源代码写的也非常不错,大量使用了queue和异步Thread的处理模式,真是一个伟大的产品。
云栖社区站内文章,如需转载,请保留作者和出处(云栖社区),并邮件通知云栖社区(yqeditor@list.alibaba-inc.com)。
zookeeper项目使用几点小结的更多相关文章
- 使用javac编译zookeeper项目
这里记录zookeeper编译源代码上的一些细节的问题. 网上不少关于如何使用ant eclipse来构建zookeeper对应的eclipse工程的记录.这里就不再过多赘述.只做简单阐述. 这里主要 ...
- springmvc 项目完整示例03 小结
利用spring 创建一个web项目 大致原理 利用spring的ioc 原理,例子中也就是体现在了配置文件中 设置了自动扫描注解 配置了数据库信息等 一般一个项目,主要有domain,dao,ser ...
- 第一个dubbo+zookeeper项目例子
公司项目要用这两个东西,于是打算学习它. 首先我的理解dubbo是什么?zookeeper是什么?为什要这么搞. 项目分层: 传统的,mvc -->垂直架构(将模块抽取成单独项目,项目互相调用) ...
- maven dubbo zookeeper 项目搭建(有效)jar包非war测试
zookeeper安装以及dubbo-admin.war(管理端)配置启动,本章省略,参考其他内容 这里主要说服务提供者和消费者 项目结构: 1)服务端 DemoServer.java package ...
- .Net 项目代码风格要求小结
代码风格没有正确与否,重要的是整齐划一,这是我拟的一份<.Net 项目代码风格要求>,供大家参考. 1. C# 代码风格要求1.1注释 类型.属性.事件.方法.方法参数,根据需要添加注释. ...
- git文件夹下项目更改ip地址小结
在我们开发的过程中,经常切换项目IP地址是很正常的,之前弄过一次,没有记住,现在简单的总结下: 找到要切换IP地址的项目,点击鼠标右键,弹出下图: 打开该项目的路径后,双击打开该项目,具体参考自己项目 ...
- Zookeeper项目开发环境搭建(Eclipse\MyEclipse + Maven)
写在前面的话 可详细参考,一定得去看 HBase 开发环境搭建(Eclipse\MyEclipse + Maven) 我这里,相信,能看此博客的朋友,想必是有一定基础的了.我前期写了大量的基础性博文. ...
- eclipse maven jdk1.8 还原站点项目红感叹号总是小结
问题背景有三 maven 默认是jdk1.5jdk1.8 目录文件夹不全操作: 在项目上右击-> build path-->config build path-->libraries ...
- 【Zookeeper学习】Apache Zookeeper项目简介
正在撰写,稍后来访……
随机推荐
- 微信openid的单脚本获取 将 header 至自身,但是reques参数不同,响应也不同-----“单脚本APP”
w 0-目的是封装成一个类.方法,方便在不同入口下,比如不是在微信公众号内而是在他人分享的url,获取opeid,且便于路由控制,将路由控制交给且仅交给codeigniter; 1-任何一个网站都可以 ...
- nodejs(三)下之mangoDB
mongoDB 简介 一.什么是MongoDB ? 1.MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情况下,添加更多的节点,可以保证服务器性能. 2.Mo ...
- nodejs(三)上之express
express 简介 Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速 ...
- intellij idea 主题更换(换黑底或白底)
更换主题: File-->setting-->Appearance&Behavior-->Appearance Intellij:白底黑字 Darcula:黑底白字
- 排序算法review<2>--Shell 排序
shell排序方法也是一种插入排序算法,于1959年由D.L.Shell提出,其基本方法是:首先将带排序文件分为d1(d1<n)组,将所有彼此之间间隔为d和d的倍数的记录放在一组中,然后在组内进 ...
- Swift学习——Swift基础具体解释(一)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhenyu5211314/article/details/34807025 注:由于基础部分在Swi ...
- My Neural Network isn't working! What should I do?
参考文献:http://theorangeduck.com/page/neural-network-not-working 我的网络不起作用!该怎么办? 因此,你在深度学习方面正在开发下一个重大突破, ...
- SVM支持向量机总结
一.拉格朗日乘子法 一般,在有等式约束时使用拉格朗日乘子法,在有不等约束时使用KKT条件.这里我们先介绍拉格朗日乘子法,后面再介绍KKT条件. 比如考虑下面的组合优化的问题, 这是一个带等式约束的优化 ...
- WebHDFS vs HttpFS GateWay
基于hadoop 2.7.1版本 一.简介 1. WebHDFS官方简介: Introduction The HTTP REST API supports the complete FileSyste ...
- Spark应用提交
在 Spark 的 bin 目录中的 spark-submit 脚本用与在集群上启动应用程序.它可以通过一个统一的接口使用所有 Spark 支持的 Cluster Manager,所以您不需要专门的为 ...