idea zookeeper的使用_学习ZooKeeper源码,就从这篇开始吧

06c5bddd5cc82f95c5417c459d62806e.gif

a3e9c889b909cfb96021d7978f14c221.gif

608299ad59fdcae9b18f747ffbad48f0.gif

【ZooKeeper系列】1.ZooKeeper单机版、伪集群和集群环境搭建

【ZooKeeper系列】2.用Java实现ZooKeeper API的调用

c4d0a99e863a4003c075cb6588473397.gif

在系列的前两篇文章中,介绍了ZooKeeper环境的搭建(包括单机版、伪集群和集群),对创建、删除、修改节点等场景用命令行的方式进行了测试,让大家对ZooKeeper环境搭建及常用命令行有初步的认识,也为搭建ZooKeeper的开发环境、生产环境起到了抛砖引玉的作用。也介绍了用Java来实现API的调用,包括节点的增、删、改、查。通过对这两篇的学习,让大家对ZooKeeper的使用有了初步认识,也可用于实现系列后面篇章要介绍的命名服务、集群管理、分布式锁、负载均衡、分布式队列等。

在前两篇中,强调了阅读英文文档的重要性,也带领大家解读了部分官方文档,想传达出的理念是ZooKeeper没有想象中的那么难,阅读官方文档也没那么难。后面的篇章中,结合官方文档,在实战演练和解读源码的基础上加深理解。

上联:说你行你就行不行也行
下联:说不行就不行行也不行
横批:不服不行阅读源码就跟这个对联一模一样,就看你选上联,还是下联了!

这一篇开始源码环境的搭建。

0320f2846ea4919ab5351482cda6775c.pnghere we go0320f2846ea4919ab5351482cda6775c.png

很多老铁留言说很想研读些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%/bin
CLASSPATH=%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的项目结构。

9aff4a9b2e348ce5402a4f5d3ce57fe5.png
在这里插入图片描述

这个编译过程会比较长,差不多等了7分钟。如果编译成功,会出现如下结果:
cf31ee7fc926cb285e159461c5b62c25.png
在这里插入图片描述

4 导入IDEA

上面已经将项目编译并转成eclipse的项目结构,按eclipse的形式导入项目。

f627f7bf20db96be18df54557d36121c.png
在这里插入图片描述
328382dfa03d09aab7ff8ec6806ba193.png
在这里插入图片描述

5 特别说明

将源码导入IDEA后在org.apache.zookeeper.Version中发现很多红色警告,很明显少了org.apache.zookeeper.version.Info类。

19955bbb8717b2ad8120b59ba4615a7f.png
在这里插入图片描述

查询源码得知是用来发布的时候生成版本用的,我们只是研读源码,又不发布版本所以直接写死就ok了。
c270e862f432e008040819d61285ac7e.png
在这里插入图片描述

即新增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\\dataDir
dataLogDir=E:\\02private\\1opensource\\zk\\zookeeper\\dataLogDir

运行主类  org.apache.zookeeper.server.ZooKeeperServerMain,将zoo.cfg的完整路径配置在Program arguments。

45b8a0272ba1be4449e71574fe0577c0.png
在这里插入图片描述

运行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。

03126e77f6fb2f7b48c09b81abe0da54.png
在这里插入图片描述

在VM options配置,即指定到conf目录下的log4j.properties:
-Dlog4j.configuration=file:E:/02private/1opensource/zk/zookeeper/conf/log4j.properties

配置后重新运行ZooKeeperServerMain,输出日志如下,

6454c29d199c0f2c3f8845c905d24a40.png
在这里插入图片描述

可以得知单机版启动成功,单机版服务端地址为127.0.0.1:2181。

7 启动客户端

通过运行ZooKeeperServerMain得到的日志,可以得知ZooKeeper服务端已经启动,服务的地址为127.0.0.1:2181。启动客户端来进行连接测试。

客户端的启动类为org.apache.zookeeper.ZooKeeperMain,进行如下配置:

426047c4f151fdb2e3f45d2a3be5d9a6.png
在这里插入图片描述

即客户端连接127.0.0.1:2181,获取节点/yuanrengu的信息。

下面带领大家一起看看客户端启动的源码(org.apache.zookeeper.ZooKeeperMain)。这里要给大家说下我阅读源码的习惯,很多老铁以为阅读源码就是顺着代码看,这样也没啥不对,只是很多开源项目代码量惊人,这么个干看法,容易注意力分散也容易看花眼。我一般是基于某个功能点,从入口开始debug跑一遍,弄清这个功能的“代码线”,就像跑马圈块地儿一样,弄清楚功能有关的代码,了解参数传递的过程,这样看代码时就更有针对性,也能排除很多干扰代码。

7.1 main

main里就两行代码,通过debug得知args里包含的信息就是上面我们配置在Program arguments里的信息:

25f6ad698f12d82a63f105aedf730198.png
在这里插入图片描述

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。

dd5744872a0087d11407a46e6be0b6d8.png
在这里插入图片描述

7.1.2 parseOptions

0eb909715187f8434816557e171fb149.png
在这里插入图片描述
可以很清楚的得知解析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的调用)

下图看看几处关键信息:

b40db69363fbb53e991bdc633ef5a4a4.png
在这里插入图片描述

Integer.parseInt(cl.getOption("timeout"))为30000。

至此完成了ZooKeeperMain main = new ZooKeeperMain(args);的整个过程。简短点说就是:

  1. 解析Program arguments里的参数

  2. 连接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包含的信息:

b20aeea32d50a1d1e3db360f23f09abf.png
在这里插入图片描述

debug到processCmd(MyCommandOptions co) 就到了决战时刻。里面的processZKCmd(MyCommandOptions co)就是核心了,代码太长,只说下processZKCmd里的重点代码,获取节点/yuanrengu的信息:
2946d9d62da86397cd7109e916cf4e00.png
在这里插入图片描述

因为我之前没有创建过/yuanrengu节点,会抛异常org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /yuanrengu , 如下图所示:
b76cd31c38179ec0746945b9204cc137.png
在这里插入图片描述

经过上面的步骤后exitCode为1,执行System.exit(exitCode);退出。

至此带领大家dubug了一遍org.apache.zookeeper.ZooKeeperMain,上面我说过,阅读源码干看效果很小,只有debug才能有助于梳理流程和思路,也能清楚参数传递的过程发生了什么变化。

温馨提示

上面我们介绍了源码环境的搭建过程,运行运行主类  org.apache.zookeeper.server.ZooKeeperServerMain 启动ZooKeeper服务端,运行org.apache.zookeeper.ZooKeeperMain连接服务端。

阅读源码最好能动起来(debug)读,这样代码才是活的,干看的话代码如死水一样,容易让人索然无味!

每个人操作的方式不一样,有可能遇到的问题也不一样,搭建过程中遇到什么问题,大家可以在评论区留言。

a3e9c889b909cfb96021d7978f14c221.gif

608299ad59fdcae9b18f747ffbad48f0.gif

如果希望更多ZooKeeper的文章,务必留言告知

c4d0a99e863a4003c075cb6588473397.gif

c1392de752b42c1468059e25cef69c42.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

base target=_self是什么意思

<base target_blank>//在空白页打开 <base target_parent>//在当前页的上一页(父亲)打开 <base target_search>//在浏览器地址栏打开 <base target_self>//在当前页打开 <base target_top>//在最初(祖先)页打开 base 是地址 tar…

都才40出头,近一个月已有至少5名优秀青年学者英年早逝!健康不容忽视

全世界只有3.14 % 的人关注了爆炸吧知识近年来&#xff0c;在工作、生活的层层重压下&#xff0c;正处于事业上升期的科研人员因病逝世的消息屡屡传出。据不完全统计&#xff0c;仅仅今年10月份至今&#xff0c;短短一个多月时间里&#xff0c;已有至少5位优秀青年学者倒下。他…

基于 Spring Security 的开源统一角色访问控制系统 URACS

URACS Java语言开发的统一角色访问控制系统(Unified Role Access Control System)&#xff0c;基于Spring Security 3实现的权限控制系统 程序框架版本说明&#xff1a;Spring MVC 3.0.6 Spring Security 3.1.3 Hibernate 3.6.10 运行演示例子&#xff1a; 例子使用的是MySQL…

Chatopera 王海良:做好开源客服系统

| 作者&#xff1a;王海良| 编辑&#xff1a;刘雪洁| 设计&#xff1a;马丽娜| 责编&#xff1a;王玥敏做好开源客服系统&#xff0c;是我最近的心心念念的事情之一。我想讲的故事&#xff0c;就包括春松客服&#xff0c;一个开源的客服系统。篇章有限&#xff0c;我想从三点来…

Android之ANR异常及解决方法

ANR (Application Not Responding)   ANR定义:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制…

如何写出无法维护的代码

If builders built buildings the way programmers write programs, then the first woodpecker that came along would destroy civilization. &#xff08;如果建筑师盖房子就像程序员写程序一样&#xff0c;那么&#xff0c;第一只到来的啄木鸟就能毁掉我们的文明&#xff0…

mysql_contents_将MySQLhelpcontents的内容有层次的输出方法推荐

经常会遇到这种情况&#xff0c;在一个不能上网的环境通过MySQL客户端登录数据库&#xff0c;想执行一个操作&#xff0c;却忘了操作的具体语法&#xff0c;各种不方便。其实&#xff0c;MySQL数据库内置了帮助文档&#xff0c;通过help contents即可查看。如下所示&#xff1a…

Android类参考---Fragment(一)

1. 继承关系 java.lang.Object |__android.app.Fragment 实现接口&#xff1a;ComponentCallbacks2 View.OnCreateContextMenuListener 引入版本&#xff1a;API Level 11 已知的子类&#xff1a; DialogFragment、ListFragment、PreferenceFragment、WebViewFragment 2. 类概要…

点开那些优秀的硕博士们的朋友圈,他们都有这些特点!

全世界只有3.14 % 的人关注了爆炸吧知识很多同学都会有这种感觉&#xff0c;读了硕士博士后&#xff0c;兴趣会突然间发生很大变化&#xff0c;发朋友圈也会不一样了。例如&#xff0c;合格的学术研究者&#xff0c;要快速、全面的获取各种最新文献和学界动态&#xff1b;还要持…

对程序员职业的一些建议

&#xff08;转载自Bcwhy编程十万个为什么&#xff09;  从四年前被CSDN采访后职业规化就像软件工程”&#xff09;&#xff0c;经常会有网友&#xff08;尤其是刚毕业的&#xff09;写邮件来问我一些程序员职业生涯的一些问题&#xff0c;至到今天。比如&#xff0c;国企还是…

如何高效的将 DataReader 转成 ListT ?

咨询区 Anthony&#xff1a;我在使用第三方工具包&#xff0c;它返回了一个 DataReader&#xff0c;为了能更方便的使用&#xff0c;我希望有一种快捷方法能够将它转成 List<T>&#xff0c;除了一行一行的迭代赋值之外还有其他好的方式吗&#xff1f;回答区 pim&#xff…

Android之如何成为Android高手

成为Android高手一般分为六个阶段&#xff1a; 第一阶段&#xff1a;熟练掌握Java SE&#xff0c;尤其是对其内部类、线程、并发、网络编程等需要深入研究&#xff1b;熟练掌握基于HTTP协议的编程&#xff0c;清楚POST和GET等请求方式流程和细节&#xff1b;能够进行基本的Java…

java foreach 跳过本次循环_【Java】对foreach循环的思考

阿里java开发手册已经发表&#xff0c;很多都值得认真研究思考&#xff0c;看到零度的思考题&#xff0c;没忍住研究了一下。在这里插入图片描述首先&#xff0c;看一下给出的反例的执行结果。如果是"1"&#xff0c;最后list中的元素为["2"]如果把"1&…

地球上这10个奇幻景观,带你踏入外太空

全世界只有3.14 % 的人关注了爆炸吧知识大蓝洞大蓝洞是灯塔礁的一部分&#xff0c;位于洪都拉斯伯利兹城陆地大约100公里之遥&#xff0c;是一个较大的完美环状海洋深洞&#xff0c;是当今世界最吸引人的潜水地点之一。305米的口径&#xff0c;123米的洞深&#xff0c;洞口呈现…

闲谈简单设计(KISS)疑惑

忙碌了一年了项目又到了交付了&#xff0c;虽然项目能成功上线&#xff08;因为还有维护支持的团队&#xff09;。但是个人从技术上看&#xff0c;这是一个不那么成功的项目&#xff0c;因为后期艰难的修复bug,添加feature。这与简单设计有什么关系呢&#xff1f;在某模块开发起…

OSChina 周六乱弹 —— 有人骂你神经病怎么办?

2019独角兽企业重金招聘Python工程师标准>>> 周六了&#xff0c;大家有没有在认真加班呢&#xff1f;其实咱们程序员的生活真的不容易 熊大信了熊二的话&#xff1a;程序员的人生 码代码不容易&#xff0c;咱们还是去抢银行吧 sunny_chan&#xff1a;一天老师让同学…

手把手教你学Dapr - 6. 发布订阅

介绍发布/订阅模式允许微服务使用消息相互通信。生产者或发布者在不知道哪个应用程序将接收它们的情况下向主题发送消息。这涉及将它们写入输入通道。同样&#xff0c;消费者或订阅者订阅该主题并接收其消息&#xff0c;而不知道是什么服务产生了这些消息。这涉及从输出通道接收…

Android之AndroidManifest.xml文件解析和权限集合

一、关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文件。它位于整个项目的根目录&#xff0c;描述了package中暴露的组件&#xff08;activities, services, 等等&#xff09;&#xff0c;他们各自的实现类&#xff0c;各种能被处理的数据和启动位置…

mysql许多连接错误而被阻止_怎样解决mysql连接过多的错误?

设置max_execution_time 来阻止太长的读SQL。那可能存在的问题是会把所有长SQL都给KILL 掉。有些必须要执行很长时间的也会被误杀。自己写个脚本检测这类语句&#xff0c;比如order by rand()&#xff0c; 超过一定时间用Kill query thread_id 给杀掉。那能不能不要杀掉而让他正…

直男的浪漫有多可怕?

1 你不说估计没人知道&#xff08;via.信箱说i&#xff09;▼2 举报&#xff0c;此处有个疑似小偷的人&#xff01;&#xff08;via&#xff1a;不知姓名的C&#xff09;▼3 世界上最互相信任的人了吧&#xff1f;▼4 你看我这个垫肩是不是很不错&#xff01;&#xff08;素…