idea zookeeper的使用_学习ZooKeeper源码,就从这篇开始吧
【ZooKeeper系列】1.ZooKeeper单机版、伪集群和集群环境搭建
【ZooKeeper系列】2.用Java实现ZooKeeper API的调用
在系列的前两篇文章中,介绍了ZooKeeper环境的搭建(包括单机版、伪集群和集群),对创建、删除、修改节点等场景用命令行的方式进行了测试,让大家对ZooKeeper环境搭建及常用命令行有初步的认识,也为搭建ZooKeeper的开发环境、生产环境起到了抛砖引玉的作用。也介绍了用Java来实现API的调用,包括节点的增、删、改、查。通过对这两篇的学习,让大家对ZooKeeper的使用有了初步认识,也可用于实现系列后面篇章要介绍的命名服务、集群管理、分布式锁、负载均衡、分布式队列等。
在前两篇中,强调了阅读英文文档的重要性,也带领大家解读了部分官方文档,想传达出的理念是ZooKeeper没有想象中的那么难,阅读官方文档也没那么难。后面的篇章中,结合官方文档,在实战演练和解读源码的基础上加深理解。
上联:说你行你就行不行也行
下联:说不行就不行行也不行
横批:不服不行阅读源码就跟这个对联一模一样,就看你选上联,还是下联了!
这一篇开始源码环境的搭建。
here we go
很多老铁留言说很想研读些github上的开源项目,但代码clone下来后总出现这样或那样奇奇怪怪的问题,很影响学习的积极性。学习ZooKeeper的源码尤其如此,很多人clone代码后,报各种错,提示少各种包。问了下度娘ZooKeeper源码环境,搜出来的文章真的差强人意,有些文章错的竟然非常离谱。这里我重新搭建了一遍,也会介绍遇到的一些坑。
很多老铁上来一堆猛操作,从github上下载了ZooKeeper源码后,按常规方式导入IDEA,最后发现少各种包。起初我也是这样弄的,以为ZooKeeper是用Maven来构建的,仔细去了解了下ZooKeeper的版本历史,其实是用的Ant。如今一般用的Maven或Gradle,很少见到Ant的项目了,这里不对Ant多做介绍。
1 Ant环境搭建
Ant官网地址:https://ant.apache.org/bindownload.cgi
下载解压后,跟配置jdk一样配置几个环境变量:
//修改为自己本地安装的目录ANT_HOMT=D:\apache-ant-1.10.7 PATH=%ANT_HOME%/binCLASSPATH=%ANT_HOME%/lib
配置好后,测试下Ant是否安装成功。ant -version,得到如下信息则代表安装成功:
Apache Ant(TM) version 1.10.7 compiled on September 1 2019
Ant的安装跟JDK的安装和配置非常相似,这里不做过多介绍。
2 下载ZooKeeper源码
源码地址:https://github.com/apache/zookeeper
猿人谷在写本篇文章时,releases列表里的最新版本为release-3.5.6
,我们以此版本来进行源码环境的搭建。
3 编译ZooKeeper源码
切换到源码所在目录,运行ant eclipse
将项目编译并转成eclipse的项目结构。
这个编译过程会比较长,差不多等了7分钟。如果编译成功,会出现如下结果:
4 导入IDEA
上面已经将项目编译并转成eclipse的项目结构,按eclipse的形式导入项目。
5 特别说明
将源码导入IDEA后在org.apache.zookeeper.Version
中发现很多红色警告,很明显少了org.apache.zookeeper.version.Info
类。
查询源码得知是用来发布的时候生成版本用的,我们只是研读源码,又不发布版本所以直接写死就ok了。
即新增Info类:
package org.apache.zookeeper.version;
public interface Info { int MAJOR = 3; int MINOR = 5; int MICRO = 6; String QUALIFIER = null; String REVISION_HASH = "c11b7e26bc554b8523dc929761dd28808913f091"; String BUILD_DATE = "10/08/2019 20:18 GMT";}
6 启动zookeeper
针对单机版本和集群版本,分别对应两个启动类:
单机:ZooKeeperServerMain
集群:QuorumPeerMain
这里我们只做单机版的测试。
在conf目录里有个zoo_sample.cfg,复制一份重命名为zoo.cfg。
zoo.cfg里的内容做点修改(也可以不做修改),方便日志查询。dataDir和dataLogDir根据自己的情况设定。
dataDir=E:\\02private\\1opensource\\zk\\zookeeper\\dataDirdataLogDir=E:\\02private\\1opensource\\zk\\zookeeper\\dataLogDir
运行主类 org.apache.zookeeper.server.ZooKeeperServerMain
,将zoo.cfg的完整路径配置在Program arguments。
运行ZooKeeperServerMain
,得到的结果如下:
Connected to the target VM, address: '127.0.0.1:0', transport: 'socket'log4j:WARN No appenders could be found for logger (org.apache.zookeeper.jmx.ManagedUtil).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
告知日志无法输出,日志文件配置有误。这里需要指定日志文件log4j.properties。
在VM options配置,即指定到conf目录下的log4j.properties:
-Dlog4j.configuration=file:E:/02private/1opensource/zk/zookeeper/conf/log4j.properties
配置后重新运行ZooKeeperServerMain
,输出日志如下,
可以得知单机版启动成功,单机版服务端地址为127.0.0.1:2181。
7 启动客户端
通过运行ZooKeeperServerMain
得到的日志,可以得知ZooKeeper服务端已经启动,服务的地址为127.0.0.1:2181
。启动客户端来进行连接测试。
客户端的启动类为org.apache.zookeeper.ZooKeeperMain
,进行如下配置:
即客户端连接127.0.0.1:2181,获取节点/yuanrengu
的信息。
下面带领大家一起看看客户端启动的源码(org.apache.zookeeper.ZooKeeperMain
)。这里要给大家说下我阅读源码的习惯,很多老铁以为阅读源码就是顺着代码看,这样也没啥不对,只是很多开源项目代码量惊人,这么个干看法,容易注意力分散也容易看花眼。我一般是基于某个功能点,从入口开始debug跑一遍,弄清这个功能的“代码线”,就像跑马圈块地儿一样,弄清楚功能有关的代码,了解参数传递的过程,这样看代码时就更有针对性,也能排除很多干扰代码。
7.1 main
main里就两行代码,通过debug得知args里包含的信息就是上面我们配置在Program arguments里的信息:
7.1.1 ZooKeeperMain
public ZooKeeperMain(String args[]) throws IOException, InterruptedException { // 用于解析参数里的命令行的 cl.parseOptions(args); System.out.println("Connecting to " + cl.getOption("server")); // 用于连接ZooKeeper服务端 connectToZK(cl.getOption("server")); }
通过下图可以看出,解析参数后,就尝试连接127.0.0.1:2181,即ZooKeeper服务端。cl.getOption("server")得到的就是127.0.0.1:2181。
7.1.2 parseOptions
可以很清楚的得知解析args的过程,主要从"-server","-timeout","-r","-"这几个维度来进行解析。
7.1.3 connectToZK
protected void connectToZK(String newHost) throws InterruptedException, IOException { // 用于判断现在ZooKeeper连接是否还有效 // zk.getState().isAlive() 注意这个会话是否有效的判断,客户端与 Zookeeper连接断开不一定会话失效 if (zk != null && zk.getState().isAlive()) { zk.close(); }
// 此时newHost为127.0.0.1:2181 host = newHost; // 判断是否为只读模式,关于只读模式的概念在前一篇文章中有介绍 boolean readOnly = cl.getOption("readonly") != null; // 用于判断是否建立安全连接 if (cl.getOption("secure") != null) { System.setProperty(ZKClientConfig.SECURE_CLIENT, "true"); System.out.println("Secure connection is enabled"); } zk = new ZooKeeperAdmin(host, Integer.parseInt(cl.getOption("timeout")), new MyWatcher(), readOnly); }
ZKClientConfig.SECURE_CLIENT
已经被标注为deprecation了:
/** * Setting this to "true" will enable encrypted client-server communication. */ @SuppressWarnings("deprecation") public static final String SECURE_CLIENT = ZooKeeper.SECURE_CLIENT;
debug查看关键点处的信息,可以得知这是建立一个ZooKeeper连接的过程(【ZooKeeper系列】2.用Java实现ZooKeeper API的调用)
下图看看几处关键信息:
Integer.parseInt(cl.getOption("timeout"))为30000。
至此完成了ZooKeeperMain main = new ZooKeeperMain(args);的整个过程。简短点说就是:
解析Program arguments里的参数
连接ZooKeeper服务端
7.2 main.run()
敲黑板,重头戏来了哦!
一起来看下run()的代码:
void run() throws CliException, IOException, InterruptedException { // cl.getCommand()得到的是 “get”,就是上文传进来的 if (cl.getCommand() == null) { System.out.println("Welcome to ZooKeeper!");
boolean jlinemissing = false; // only use jline if it's in the classpath try { Class> consoleC = Class.forName("jline.console.ConsoleReader"); Class> completorC = Class.forName("org.apache.zookeeper.JLineZNodeCompleter");
System.out.println("JLine support is enabled");
Object console = consoleC.getConstructor().newInstance();
Object completor = completorC.getConstructor(ZooKeeper.class).newInstance(zk); Method addCompletor = consoleC.getMethod("addCompleter", Class.forName("jline.console.completer.Completer")); addCompletor.invoke(console, completor);
String line; Method readLine = consoleC.getMethod("readLine", String.class); while ((line = (String)readLine.invoke(console, getPrompt())) != null) { executeLine(line); } } catch (ClassNotFoundException e) { LOG.debug("Unable to start jline", e); jlinemissing = true; } catch (NoSuchMethodException e) { LOG.debug("Unable to start jline", e); jlinemissing = true; } catch (InvocationTargetException e) { LOG.debug("Unable to start jline", e); jlinemissing = true; } catch (IllegalAccessException e) { LOG.debug("Unable to start jline", e); jlinemissing = true; } catch (InstantiationException e) { LOG.debug("Unable to start jline", e); jlinemissing = true; }
if (jlinemissing) { System.out.println("JLine support is disabled"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line; while ((line = br.readLine()) != null) { executeLine(line); } } } else { // 处理传进来的参数 processCmd(cl); } System.exit(exitCode); }
通过下图可以看出processCmd(cl);
里cl
包含的信息:
debug到processCmd(MyCommandOptions co)
就到了决战时刻。里面的processZKCmd(MyCommandOptions co)
就是核心了,代码太长,只说下processZKCmd里的重点代码,获取节点/yuanrengu的信息:
因为我之前没有创建过/yuanrengu节点,会抛异常org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /yuanrengu
, 如下图所示:
经过上面的步骤后exitCode为1,执行System.exit(exitCode);退出。
至此带领大家dubug了一遍org.apache.zookeeper.ZooKeeperMain,上面我说过,阅读源码干看效果很小,只有debug才能有助于梳理流程和思路,也能清楚参数传递的过程发生了什么变化。
温馨提示
上面我们介绍了源码环境的搭建过程,运行运行主类 org.apache.zookeeper.server.ZooKeeperServerMain
启动ZooKeeper服务端,运行org.apache.zookeeper.ZooKeeperMain
连接服务端。
阅读源码最好能动起来(debug)读,这样代码才是活的,干看的话代码如死水一样,容易让人索然无味!
每个人操作的方式不一样,有可能遇到的问题也不一样,搭建过程中遇到什么问题,大家可以在评论区留言。
如果希望更多ZooKeeper的文章,务必留言告知
idea zookeeper的使用_学习ZooKeeper源码,就从这篇开始吧相关推荐
- vue filter对象_学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法
一.Vue.directive Vue.directive(id,[definition]); 1)参数 { string } id{ Function | Object } [ definition ...
- mysql数据库源码安装_学习笔记-源码安装mariadb 20210128
源码安装Mariadb数据库 安装之前先检查一下空间: 1 [15:13:16 root@centos8 ~]#free -h(#检查空间)2 total used free shared buff/ ...
- 学习 vuex 源码整体架构,打造属于自己的状态管理库
前言 这是学习源码整体架构第五篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 其余四篇分别是: ...
- 学习 redux 源码整体架构,深入理解 redux 及其中间件原理
如果觉得内容不错,可以设为星标置顶我的公众号 1. 前言 你好,我是若川.这是学习源码整体架构系列第八篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是 ...
- 学习 sentry 源码整体架构,打造属于自己的前端异常监控SDK
前言 这是学习源码整体架构第四篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.文章学习的是打包整合后的代码,不是实际仓库中的拆分 ...
- 学习 lodash 源码整体架构,打造属于自己的函数式编程类库
前言 这是 学习源码整体架构系列第三篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.文章学习的是打包整合后的代码,不是实际仓库中 ...
- 学习underscore源码整体架构,打造属于自己的函数式编程类库
前言 上一篇文章写了 jQuery整体架构,学习 jQuery 源码整体架构,打造属于自己的 js 类库 虽然看过挺多 underscore.js分析类的文章,但总感觉少点什么.这也许就是纸上得来终觉 ...
- 学习 jQuery 源码整体架构,打造属于自己的 js 类库
虽然现在基本不怎么使用 jQuery了,但 jQuery流行 10多年的 JS库,还是有必要学习它的源码的.也可以学着打造属于自己的 js类库,求职面试时可以增色不少. 本文章学习的是 v3.4.1版 ...
- 学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理
前言 这是学习源码整体架构系列第七篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 学习源码整体 ...
最新文章
- GEO数据挖掘(2)-GEO数据库
- java的自动装箱和拆箱,Java中的自动装箱和拆箱是什么?
- 使用Oracle LogMiner分析archived log
- php怎么根据接口文档实现功能,CodeIgniter+swagger实现 PHP API接口文档自动生成功能...
- hexo评论_Hexo系列 | Hexo的基本使用
- Linux下搭建asp.net运行环境
- 算法学习笔记(5)-------位运算的tips
- android studio 经验
- python比flask更好的框架_(入门篇)Python框架之FastAPI——一个比Flask和Tornado更高性能的API 框架...
- LINUX 下 RABBITMQ安装与配置
- Unity手游开发与实战
- java获取access token_使用java代码获取新浪微博应用的access token代码实例
- Java虚拟机内存管理
- C++——模板(超详细的模板解析)
- UA OPTI512R 傅立叶光学导论1 为什么光学需要傅立叶变换
- 同时开多个独立窗口Visio 2003/2007版本的软件
- 人工智能一种现代的方法 --第2章 智能Agent
- java读取tif文件_java读取TIF,TIFF文件方法
- 火狐浏览器插件汇总(VIP典藏版)
- nanomsg安装和测试
热门文章
- 自动给 Asp.Net Core Api 增加 ApiVersionNeutral
- 书籍推荐:《More Effective C#》
- 东莞.NET技术线下沙龙活动资料分享
- 为什么 web 开发人员需要迁移到. NET Core, 并使用 ASP.NET Core MVC 构建 web 和 API
- C#热度不如Java?网友呛声:还有使用C#不能完成的工作?
- IdentityServer4 实现自定义 GrantType 授权模式
- asp.net core 负载均衡集群搭建(centos7+nginx+supervisor+kestrel)
- WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例
- rest_framework10:base64补充/修改头像
- crossphp框架中,在模板中加载其他模板