【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);的整个过程。简短点说就是:

  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包含的信息:

在这里插入图片描述

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源码,就从这篇开始吧相关推荐

  1. vue filter对象_学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法

    一.Vue.directive Vue.directive(id,[definition]); 1)参数 { string } id{ Function | Object } [ definition ...

  2. mysql数据库源码安装_学习笔记-源码安装mariadb 20210128

    源码安装Mariadb数据库 安装之前先检查一下空间: 1 [15:13:16 root@centos8 ~]#free -h(#检查空间)2 total used free shared buff/ ...

  3. 学习 vuex 源码整体架构,打造属于自己的状态管理库

    前言 这是学习源码整体架构第五篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 其余四篇分别是: ...

  4. 学习 redux 源码整体架构,深入理解 redux 及其中间件原理

    如果觉得内容不错,可以设为星标置顶我的公众号 1. 前言 你好,我是若川.这是学习源码整体架构系列第八篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是 ...

  5. 学习 sentry 源码整体架构,打造属于自己的前端异常监控SDK

    前言 这是学习源码整体架构第四篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.文章学习的是打包整合后的代码,不是实际仓库中的拆分 ...

  6. 学习 lodash 源码整体架构,打造属于自己的函数式编程类库

    前言 这是 学习源码整体架构系列第三篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.文章学习的是打包整合后的代码,不是实际仓库中 ...

  7. 学习underscore源码整体架构,打造属于自己的函数式编程类库

    前言 上一篇文章写了 jQuery整体架构,学习 jQuery 源码整体架构,打造属于自己的 js 类库 虽然看过挺多 underscore.js分析类的文章,但总感觉少点什么.这也许就是纸上得来终觉 ...

  8. 学习 jQuery 源码整体架构,打造属于自己的 js 类库

    虽然现在基本不怎么使用 jQuery了,但 jQuery流行 10多年的 JS库,还是有必要学习它的源码的.也可以学着打造属于自己的 js类库,求职面试时可以增色不少. 本文章学习的是 v3.4.1版 ...

  9. 学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理

    前言 这是学习源码整体架构系列第七篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 学习源码整体 ...

最新文章

  1. GEO数据挖掘(2)-GEO数据库
  2. java的自动装箱和拆箱,Java中的自动装箱和拆箱是什么?
  3. 使用Oracle LogMiner分析archived log
  4. php怎么根据接口文档实现功能,CodeIgniter+swagger实现 PHP API接口文档自动生成功能...
  5. hexo评论_Hexo系列 | Hexo的基本使用
  6. Linux下搭建asp.net运行环境
  7. 算法学习笔记(5)-------位运算的tips
  8. android studio 经验
  9. python比flask更好的框架_(入门篇)Python框架之FastAPI——一个比Flask和Tornado更高性能的API 框架...
  10. LINUX 下 RABBITMQ安装与配置
  11. Unity手游开发与实战
  12. java获取access token_使用java代码获取新浪微博应用的access token代码实例
  13. Java虚拟机内存管理
  14. C++——模板(超详细的模板解析)
  15. UA OPTI512R 傅立叶光学导论1 为什么光学需要傅立叶变换
  16. 同时开多个独立窗口Visio 2003/2007版本的软件
  17. 人工智能一种现代的方法 --第2章 智能Agent
  18. java读取tif文件_java读取TIF,TIFF文件方法
  19. 火狐浏览器插件汇总(VIP典藏版)
  20. nanomsg安装和测试

热门文章

  1. 自动给 Asp.Net Core Api 增加 ApiVersionNeutral
  2. 书籍推荐:《More Effective C#》
  3. 东莞.NET技术线下沙龙活动资料分享
  4. 为什么 web 开发人员需要迁移到. NET Core, 并使用 ASP.NET Core MVC 构建 web 和 API
  5. C#热度不如Java?网友呛声:还有使用C#不能完成的工作?
  6. IdentityServer4 实现自定义 GrantType 授权模式
  7. asp.net core 负载均衡集群搭建(centos7+nginx+supervisor+kestrel)
  8. WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例
  9. rest_framework10:base64补充/修改头像
  10. crossphp框架中,在模板中加载其他模板