经过前面第一章四节的学习,相信你已经对zookeeper场景的原理、使用场景、部署和运维都有了基本的认识。希望你尽可能去了解下公司使用zookeeper的现状,起码当你们使用zookeeper时或者面试时问到zookeeper时不至于什么都不知道。
第一章知识是基础,如果你对zookeeper是指停留在create、delete一个node或者使用zookeeper用作分布锁这些基本使用上,平常工作肯定没有问题。但是如果使用出现了各种问题时,你可能毫无头绪,因为你压根不知道它底层的源码实现原理,对一个报错的堆栈都很陌生。你可能只能百度下解决办法,但是还得分辨答案的对错,而且很多文章没有上下文,交代软件版本,系统配置等等,问题不一定是和你遇见的一样。或者你研究其他中间件源码的时候,看到它使用了zookeeper,不知道它为什么那么用。
所以这就是研究源码的原理的原因之一了,简单的说就是,搞清楚你使用的技术,方便定位生产线上问题。
至于提高你自己的技术深度,面试什么的,那就更没什么问题了。而且我也希望当你可以自己研发中间件或者参与开源项目的时候,使用zookeeper可以更得心应手、游刃有余。
好了,那么接下来你就我一起进入第二章,一起研究zookeepe核心源码原理吧。
第二章 Zookeeper的源码原理
第 1 节
zookeeper源码原理起步
如何看zk的源码
从zookeeper的架构,你可以知道zookeeper主要分为服务端和客户端。我想你首先感兴趣的应该就是服务端的源码了,所以我们就先从服务端源码开始分析。
那么如何看源码呢?
各位还记得JDK成长记开篇我曾经提到过的一些的方法和思想么?我来带大家回顾下:
首先说源码版本的选择和获取。
源码版本选择的话,通常是选择上一个大版本,并且是release之前的2到3个小版本。比如2.4.13和3.0.1,肯定是2.4.13的好一点,如果2.4的版本还在持续更新,最好选择2.4.10这个release版本。因为最新的不一定有人在用,除了问题不好查,因为没有新版本的一些经验。其实如果你懂一些运维的话,这个是部署版本的选择的一个常见思路,其实和源码选择版本是大同小异的。
但是不是所有的都这么通用。其实就是选择最流行的,最稳定的版本就行。最好的是,你可以自己查下公司生产环境使用的版本,朋友公司使用的版本,一般都是非常稳定的版本,阅读这个版本的源码一般是没问题的。
当然有些时候,你需要阅读的源码可能随着版本有很大的重构。这个时候也要注意,选择版本低一些的可能更好容易理解。理解了简单的版本,再理解复杂的,才是比较好的一个思路。
你可以看出来,选择源码的版本不能一概而论。要根据具体情况来的,上面的只是我的一些建议和经验。希望可以帮助到你们。
至于源码版本获取一般以下几种
下载源码导入Intellij等IDE,来阅读代码
开启Maven自动下载源码的功能
自己从官方(如Github)或者Maven仓库手动下载源码
这几种都可以获取到源码,各有各的适用场景,比如如果你想写些注释,就需要导入到IDE才行,比如你想Debug源码,不需要把源码导入到IDE中,适用2,3的方法都可以。又比如有些代码Maven仓库根本没有,只能从Github或官方下载了。
其次,我们聊下,阅读静态源码还是动态源码?这个取决于源码的复杂程度、你阅读源码的能力等。如果是一些简单的源码或者你有很多阅读源码的经验了,一般阅读静态源码就足够了。但是如果是小白,或者真的源码比较复杂,又或者你需要具体看看执行过程中的某个变量和返回值,你肯定需要debug进行动态源码阅读了。但是要注意debug会打断集群的一些交互,可能会影响到阅读源码,这个是你要权衡的。
当你打开源码,肯定不是直接就开始从头开始看一遍,这样会一头雾水,所以肯定是有思路和方法可寻的。
在这里,首先你要明白,看核心源码和精读源码的方式不太一样。看核心源码,也就是核心部分的源码,一般也就是10-30%。你应该都是从一些入口开始看起,但是如果你要精读源码,除了在阅读核心源码的基础上,你还需要将源码拆解开来,研究每一个组件的各个作用,之后再从入口开始,一行一行都读懂。
这其实体现了一个很重要的思想,无论做什么事,先摸脉络,后看细节。就比如瞎子摸象一样,你每个部位摸了一遍,但是没有全局的认识,这就很搞笑了。所以一般你应该先看核心源码再精读源码。
除了先摸脉络,后看细节的思想,常见的还有:
自顶而下或自底而上
抓大放小
先脉络,后细节
连猜带蒙
结合功能场景逐个分析
方法就更多了,主要有:
看注释
加注释
画图
Debug
观察日志或增加日志
……
上面这些,之后我都会带大家使用到的,并且你会学会在合适的场景使用上,你只要持续关注成长记就可以了。
最后,还要说一点,有人说阅读源码,需要很多技术基础,的确没错。但是也分是什么样的源码,如果只是简单的源码,需要的基础知识会很少,比如JDK的源码。但是如果比较难的源码,Zookeeper、HDFS、Kafka、Dubbo这些源码,就需要掌握Netty,NIO,网络,Java集合和并发等基础才能看得更好。当然如果没有这些基础也不是不能看的,就是理解可能不会深,对源码最后可能只是初步了解。所以还是那句话,不要一概而论。
简单总结下:
ZK源码版本选择和环境搭建
zookeeper的版本已经非常稳定了,最新的是3.7.0,生产常用的是3.4.xx版本,3.4最新的是3.4.14版本,我们可以往之前推几个版本,这里选择3.4.5版本的源码来阅读就可以了。
1) 下载ant和zookeeper
从这个网址 https://archive.apache.org/dist/zookeeper/,找到zookeeper-3.4.5.tar.gz的下载链接进行下载。
解压出来如下:
可以发现,zookeeper这个版本比较老了,使用的构建工具是ant+ivy。(类似于maven的功能)
所以需要下载项目构建工具,只下载ant就可以了,下载比较新的版本就行了
apache-ant-1.10.5:https://archive.apache.org/dist/ant/binaries/
2) 使用ant构建项目
将ant的bin目录配置到系统环境变量,可以全局执行ant命令。执行构建命令ant eclipse
配置系统环境变量:Windows在PATH中添加 D:\Tools\apache-ant-1.10.5\bin,Mac类似。
D:\AllWorkspace\zookeeper-3.4.5>ant eclipse
Buildfile: D:\AllWorkspace\zookeeper-3.4.5\build.xml
ant-eclipse-download:
init:
ivy-download
ivy-taskdef:
ivy-init:
[ivy:cachepath] :: resolving dependencies :: org.apache.zookeeper#zookeeper;3.4.5 [not transitive]
[ivy:cachepath] confs: [test]
[ivy:cachepath] found junit#junit;4.8.1 in maven2
[ivy:cachepath] found org.mockito#mockito-all;1.8.2 in maven2
[ivy:cachepath] found checkstyle#checkstyle;5.0 in maven2
[ivy:cachepath] :: resolution report :: resolve 30ms :: artifacts dl 2ms
---------------------------------------------------------------------
| | modules || artifacts |
| conf | number| search|dwnlded|evicted|| number|dwnlded|
---------------------------------------------------------------------
| test | 3 | 0 | 0 | 0 || 3 | 0 |
---------------------------------------------------------------------
[eclipse] Writing the preferences for "org.eclipse.jdt.core".
[eclipse] Writing the preferences for "org.eclipse.core.resources".
[eclipse] Writing the project definition in the mode "java".
[eclipse] Writing the classpath definition.
BUILD SUCCESSFUL
Total time: 36 seconds
可以看到生成了.project的文件。
Tips:http://repo2.maven.org解析失败,需要修改配置文件中的url地址为https://repo1.maven.org。
build.xml
<property name="ivy.url" value="https://repo1.maven.org/maven2/org/apache/ivy/ivy" />
ivysettings.xml
<property name="repo.maven.org" value="https://repo1.maven.org/maven2/" override="false"/>
3)导入intelliJ
选择菜单中File->New->Project from existing Source...
选择目录中的.project文件
导入源码就完成了,src目录
下的就是我们主要看的源码了。
源码入口寻找
研究中间件的源码时,常用的思想就是自顶向下+场景分析法。说白了就是找到某个场景的入口,再开始逐步分析它的源码原理。
那么,你可以想到对于zk而言,你首先分析的第一个场景是什么呢?当然是zk的启动了,你在部署zk时,肯定执行了一个启动命令,这个命令肯定对应了一个启动的脚本,所以一般来说,启动的场景我们可以从启动脚本开始分析,就可以找到这个场景的源码入口了。
你还记得部署zk,启动时的脚本吗?zkServer.sh start对应的核心启动代码如下:
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
#通过nohup启动一个后台线程,启动入口就是之前的ZOOMAIN变量指定的代码类
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
可以看到zk启动主要是通过zkServer.sh start,之后设置了一个环境变量ZOOMAIN,在之后通过nohup启动了一个进程。整体大致如下图所示:
其实看到这里,你应该知道zk在启动这个场景中的源码入口是什么了。org.apache.zookeeper.server.quorum.QuorumPeerMain 就是这个类。
那么之后我们就可以通过这个入口来分析zk启动是的源码原理了。
金句甜点
今天我想谈谈“格局”这个词,很多人在看这个,或者听这个的时候不太懂什么是格局。其实格局,这个大的可以说是这个人的胸怀。胸怀能装多少人这是一种格局。装多少人的梦想,愿意为多少人扛起他的责任。有些人的格局是、一个人吃饱全家人不饿的格局。有些人的格局是我把我的家人带着过上幸福的生活,有些的人的格局还可能更大,还可能想把我的朋友,家族,身边的很多人帮助起。所以这种格局越大的人,他的动力越大。很多时候,社会上有很多有钱人,有钱人不代表有格局。有钱了,他可能就歇息下来了。也有可能帮助更多的人。
格局还可以从一个角度来理解,就一种心胸开阔,乐观心态。就比如就是当你对待一些困难和挫折的时候,格局大的人其实很容易受挫折,但是他一般不把这个事情当事情。反而格局小的人遇见一点点挫折,就很吃力。格局有时候就像口袋,口袋小的你就装着满满的,是不是?这样比喻这个就好理解了。不管你人生也好、工作也好,都会有委屈。你的委屈,可能在我这里不叫委屈,这就是格局的大小。我这里有一个大大的袋子,什么都能装下,这都不是个啥事,你那里就一个小袋袋,就撑的都难受。所以同样一件事到来你过不去,你委屈的哭。举个极端的例子,有一天我问你哭啥了,你说”我没把垃圾扔好,底下那个扫垃圾的瞪我一眼,我不是故意的,他瞪我一眼,我就委屈的过不去了。“ 这就像别人说你做错了一件事,父母说了你一顿,或者领导批评你了,路人教育你了几句话,你就想着,你凭啥这么说我呢?你自己一肚子气。这样的格局就不大了,我这么说你,你不会又说我就是格局小的人.... 我们总会有时候或多或少这样子的。但是随着你的成长,格局或者心胸会不断的变大、被撑大。到时候可能就会这么想,你们可以和我交流的,我不一定是对的,但是我们可以交换一下我们的认识。这种想法就很善、很善了。
好了今天就到这里,我们下一节再见!