zookeeper 源碼原理起步

經過前面第一章四節的學習,相信你已經對 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 版本。因爲最新的不一定有人在用,除了問題不好查,因爲沒有新版本的一些經驗。其實如果你懂一些運維的話,這個是部署版本的選擇的一個常見思路,其實和源碼選擇版本是大同小異的。

但是不是所有的都這麼通用。其實就是選擇最流行的,最穩定的版本就行。最好的是,你可以自己查下公司生產環境使用的版本,朋友公司使用的版本,一般都是非常穩定的版本,閱讀這個版本的源碼一般是沒問題的。

當然有些時候,你需要閱讀的源碼可能隨着版本有很大的重構。這個時候也要注意,選擇版本低一些的可能更好容易理解。理解了簡單的版本,再理解複雜的,纔是比較好的一個思路。

你可以看出來,選擇源碼的版本不能一概而論。要根據具體情況來的,上面的只是我的一些建議和經驗。希望可以幫助到你們。

至於源碼版本獲取一般以下幾種

  1. 下載源碼導入 Intellij 等 IDE,來閱讀代碼

  2. 開啓 Maven 自動下載源碼的功能

  3. 自己從官方(如 Github)或者 Maven 倉庫手動下載源碼

這幾種都可以獲取到源碼,各有各的適用場景,比如如果你想寫些註釋,就需要導入到 IDE 纔行,比如你想 Debug 源碼,不需要把源碼導入到 IDE 中,適用 2,3 的方法都可以。又比如有些代碼 Maven 倉庫根本沒有,只能從 Github 或官方下載了。

其次,我們聊下,閱讀靜態源碼還是動態源碼?這個取決於源碼的複雜程度、你閱讀源碼的能力等。如果是一些簡單的源碼或者你有很多閱讀源碼的經驗了,一般閱讀靜態源碼就足夠了。但是如果是小白,或者真的源碼比較複雜,又或者你需要具體看看執行過程中的某個變量和返回值,你肯定需要 debug 進行動態源碼閱讀了。但是要注意 debug 會打斷集羣的一些交互,可能會影響到閱讀源碼,這個是你要權衡的。

當你打開源碼,肯定不是直接就開始從頭開始看一遍,這樣會一頭霧水,所以肯定是有思路和方法可尋的。

在這裏,首先你要明白,看核心源碼和精讀源碼的方式不太一樣。看核心源碼,也就是核心部分的源碼,一般也就是 10-30%。你應該都是從一些入口開始看起,但是如果你要精讀源碼,除了在閱讀核心源碼的基礎上,你還需要將源碼拆解開來,研究每一個組件的各個作用,之後再從入口開始,一行一行都讀懂。

這其實體現了一個很重要的思想,無論做什麼事,先摸脈絡,後看細節。就比如瞎子摸象一樣,你每個部位摸了一遍,但是沒有全局的認識,這就很搞笑了。所以一般你應該先看核心源碼再精讀源碼。

除了先摸脈絡,後看細節的思想,常見的還有:

方法就更多了,主要有:

上面這些,之後我都會帶大家使用到的,並且你會學會在合適的場景使用上,你只要持續關注成長記就可以了。

最後,還要說一點,有人說閱讀源碼,需要很多技術基礎,的確沒錯。但是也分是什麼樣的源碼,如果只是簡單的源碼,需要的基礎知識會很少,比如 JDK 的源碼。但是如果比較難的源碼,Zookeeper、HDFS、Kafka、Dubbo 這些源碼,就需要掌握 Netty,NIO,網絡,Java 集合和併發等基礎才能看得更好。當然如果沒有這些基礎也不是不能看的,就是理解可能不會深,對源碼最後可能只是初步瞭解。所以還是那句話,不要一概而論。

簡單總結下:

ZK 源碼版本選擇和環境搭建

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  />

ivysettings.xml

<property />

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 啓動是的源碼原理了。

金句甜點

今天我想談談 “格局” 這個詞,很多人在看這個,或者聽這個的時候不太懂什麼是格局。其實格局,這個大的可以說是這個人的胸懷。胸懷能裝多少人這是一種格局。裝多少人的夢想,願意爲多少人扛起他的責任。有些人的格局是、一個人喫飽全家人不餓的格局。有些人的格局是我把我的家人帶着過上幸福的生活,有些的人的格局還可能更大,還可能想把我的朋友,家族,身邊的很多人幫助起。所以這種格局越大的人,他的動力越大。很多時候,社會上有很多有錢人,有錢人不代表有格局。有錢了,他可能就歇息下來了。也有可能幫助更多的人。

  格局還可以從一個角度來理解,就一種心胸開闊,樂觀心態。就比如就是當你對待一些困難和挫折的時候,格局大的人其實很容易受挫折,但是他一般不把這個事情當事情。反而格局小的人遇見一點點挫折,就很喫力。格局有時候就像口袋,口袋小的你就裝着滿滿的,是不是?這樣比喻這個就好理解了。不管你人生也好、工作也好,都會有委屈。你的委屈,可能在我這裏不叫委屈,這就是格局的大小。我這裏有一個大大的袋子,什麼都能裝下,這都不是個啥事,你那裏就一個小袋袋,就撐的都難受。所以同樣一件事到來你過不去,你委屈的哭。舉個極端的例子,有一天我問你哭啥了,你說” 我沒把垃圾扔好,底下那個掃垃圾的瞪我一眼,我不是故意的,他瞪我一眼,我就委屈的過不去了。“ 這就像別人說你做錯了一件事,父母說了你一頓,或者領導批評你了,路人教育你了幾句話,你就想着,你憑啥這麼說我呢?你自己一肚子氣。這樣的格局就不大了,我這麼說你,你不會又說我就是格局小的人.... 我們總會有時候或多或少這樣子的。但是隨着你的成長,格局或者心胸會不斷的變大、被撐大。到時候可能就會這麼想,你們可以和我交流的,我不一定是對的,但是我們可以交換一下我們的認識。這種想法就很善、很善了。

好了今天就到這裏,我們下一節再見!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/VDqpvixoW8xW-hOeQwIzYg