https://www.cnblogs.com/zhangs1986/p/6564839.html?from=timeline
說到分布式開發(fā)Zookeeper是必須了解和掌握的,分布式消息服務(wù)kafka 、hbase 到hadoop等分布式大數(shù)據(jù)處理都會用到Zookeeper,所以在此將Zookeeper作為基礎(chǔ)來講解。
? Zookeeper 是分布式服務(wù)框架,主要是用來解決分布式應(yīng)用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式應(yīng)用配置項的管理等等。
Zookeeper 的核心是廣播,這個機制保證了各個Server之間的同步。實現(xiàn)這個機制的協(xié)議叫做Zab協(xié)議。
Zab協(xié)議有兩種模式,它們分別是恢復(fù)模式(選主)和廣播 模式(同步)。當服務(wù)啟動或者在領(lǐng)導(dǎo)者崩潰后,Zab就進入了恢復(fù)模式,當領(lǐng)導(dǎo)者被選舉出來,且大多數(shù)Server完成了和leader的狀態(tài)同步以后, 恢復(fù)模式就結(jié)束了。
狀態(tài)同步保證了leader和Server具有相同的系統(tǒng)狀態(tài)。為了保證事務(wù)的順序一致性,zookeeper采用了遞增的事務(wù)id號 (zxid)來標識事務(wù)。
所有的提議(proposal)都在被提出的時候加上了zxid。實現(xiàn)中zxid是一個64位的數(shù)字,它高32位是epoch用 來標識leader關(guān)系是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬于那個leader的統(tǒng)治時期。低32位用于遞 增計數(shù)。
每個Server在工作過程中有三種狀態(tài):
LOOKING:當前Server不知道leader是誰,正在搜尋。
LEADING:當前Server即為選舉出來的leader。
FOLLOWING:leader已經(jīng)選舉出來,當前Server與之同步。

ZooKeeper的安裝模式分為三種,分別為:單機模式、集群模式和集群偽分布模式
環(huán)境
CentOS7.0 ?(windows中使用就使用zkServer.cmd)
ZooKeeper最新版本
用root用戶安裝(如果用于hbase時將所有文件權(quán)限改為hadoop用戶)
? ? ?Java環(huán)境,最好是最新版本的。
分布式時多機間要確保能正常通訊,關(guān)閉防火墻或讓涉及到的端口通過。
下載
去官網(wǎng)下載 :http://zookeeper.apache.org/releases.html#download
下載后放進CentOS中的/usr/local/ 文件夾中,并解壓到當前文件中 /usr/local/zookeeper(怎么解壓可參考之前的Haproxy的安裝文章)
安裝
單機模式
進入zookeeper目錄下的conf子目錄, 重命名 zoo_sample.cfg文件,Zookeeper 在啟動時會找這個文件作為默認配置文件:
mv /usr/local/zookeeper/conf/zoo_sample.cfg ?zoo.cfg
配置zoo.cfg參數(shù)
# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial # synchronization phase can takeinitLimit=10# The number of ticks that can pass between # sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just # example sakes.dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/log# the port at which the clients will connectclientPort=2181#
# Be sure to read the maintenance section of the # administrator guide before turning on autopurge.#
#http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance#
# The number of snapshots to retain in dataDir#autopurge.snapRetainCount=3# Purge task interval in hours# Set to "0" to disable auto purge feature#autopurge.purgeInterval=1
參數(shù)說明:
tickTime:毫秒值.這個時間是作為 Zookeeper 服務(wù)器之間或客戶端與服務(wù)器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發(fā)送一個心跳。
dataDir:顧名思義就是 Zookeeper 保存數(shù)據(jù)的目錄,默認情況下,Zookeeper 將寫數(shù)據(jù)的日志文件也保存在這個目錄里。
dataLogDir:顧名思義就是 Zookeeper 保存日志文件的目錄
clientPort:這個端口就是客戶端連接 Zookeeper 服務(wù)器的端口,Zookeeper 會監(jiān)聽這個端口,接受客戶端的訪問請求。
再創(chuàng)建上面配置的data和log文件夾:
mkdir? /usr/local/zookeeper/data
mkdir? /usr/local/zookeeper/log
啟動zookeeper
先進入/usr/local/zookeeper文件夾
cd /usr/local/zookeeper
再運行?
bin/zkServer.sh start
檢測是否成功啟動:執(zhí)行
bin/zkCli.sh
或
echo stat|nc localhost 2181
?偽集群模式
所謂偽集群, 是指在單臺機器中啟動多個zookeeper進程, 并組成一個集群. 以啟動3個zookeeper進程為例,模擬3臺機。
將zookeeper的目錄多拷貝2份:
zookeeper/conf/zoo.cfg文件與單機一樣,只改為下面的內(nèi)容:
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/log
clientPort=2180server.0=127.0.0.1:2888:3888server.1=127.0.0.1:2889:3889
server.2=127.0.0.1:2890:3890
新增了幾個參數(shù), 其含義如下:
1 initLimit: zookeeper集群中的包含多臺server, 其中一臺為leader, 集群中其余的server為follower. initLimit參數(shù)配置初始化連接時, follower和leader之間的最長心跳時間. 此時該參數(shù)設(shè)置為5, 說明時間限制為5倍tickTime, 即5*2000=10000ms=10s.
2 syncLimit: 該參數(shù)配置leader和follower之間發(fā)送消息, 請求和應(yīng)答的最大時間長度. 此時該參數(shù)設(shè)置為2, 說明時間限制為2倍tickTime, 即4000ms.
3 server.X=A:B:C 其中X是一個數(shù)字, 表示這是第幾號server. A是該server所在的IP地址. B配置該server和集群中的leader交換消息所使用的端口. C配置選舉leader時所使用的端口. 由于配置的是偽集群模式, 所以各個server的B, C參數(shù)必須不同.
參照zookeeper/conf/zoo.cfg, 配置zookeeper1/conf/zoo.cfg, 和zookeeper2/conf/zoo.cfg文件. 只需更改dataDir, dataLogDir, clientPort參數(shù)即可.
在之前設(shè)置的dataDir中新建myid文件, 寫入一個數(shù)字, 該數(shù)字表示這是第幾號server. 該數(shù)字必須和zoo.cfg文件中的server.X中的X一一對應(yīng).
/usr/local/zookeeper/data/myid文件中寫入0, /usr/local/zookeeper1/data/myid文件中寫入1, /Users/apple/zookeeper2/data/myid文件中寫入2.
分別進入/usr/local/zookeeper/bin, /usr/local/zookeeper1/bin, /usr/local/zookeeper2/bin三個目錄, 啟動server。啟動方法與單機一致。
bin/zkServer.sh start
分別檢測是否成功啟動:執(zhí)行
bin/zkCli.sh
或
echo stat|nc localhost 2181
集群模式
集群模式的配置和偽集群基本一致.
由于集群模式下, 各server部署在不同的機器上, 因此各server的conf/zoo.cfg文件可以完全一樣.
下面是一個示例:
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/local/zookeeper/data
dataLogDir=/usr/local/zookeeper/log
clientPort=2180server.0=192.168.80.30:2888:3888server.1=192.168.80.31:2888:3888server.2=192.168.80.32:2888:3888
示例中部署了3臺zookeeper server, 分別部署在192.168.80.30, 192.168.80.31, 192.168.80.32上.?
需要注意的是, 各server的dataDir目錄下的myid文件中的數(shù)字必須不同,192.168.80.30 server的myid為0, 192.168.80.31 server的myid為1, 192.168.80.32 server的myid為2
分別進入/usr/local/zookeeper/bin目錄, 啟動server。啟動方法與單機一致。
bin/zkServer.sh start
分別檢測是否成功啟動:執(zhí)行
bin/zkCli.sh
或
echo stat|nc localhost 2181
? 這時會報大量錯誤?其實沒什么關(guān)系,因為現(xiàn)在集群只起了1臺server,zookeeper服務(wù)器端起來會根據(jù)zoo.cfg的服務(wù)器列表發(fā)起選舉leader的請求,因為連不上其他機器而報錯,那么當我們起第二個zookeeper實例后,leader將會被選出,從而一致性服務(wù)開始可以使用,這是因為3臺機器只要有2臺可用就可以選出leader并且對外提供服務(wù)(2n+1臺機器,可以容n臺機器掛掉)。
ZooKeeper服務(wù)命令
1. 啟動ZK服務(wù): zkServer.sh start2. 查看ZK服務(wù)狀態(tài): zkServer.sh status3. 停止ZK服務(wù): zkServer.sh stop4. 重啟ZK服務(wù): zkServer.sh restart
zk客戶端命令:
ZooKeeper 命令行工具類似于Linux的shell環(huán)境,使用它可以對ZooKeeper進行訪問,數(shù)據(jù)創(chuàng)建,數(shù)據(jù)修改等操作.
使用 zkCli.sh -server 192.168.80.31:2181 連接到 ZooKeeper 服務(wù),連接成功后,系統(tǒng)會輸出 ZooKeeper 的相關(guān)環(huán)境以及配置信息。命令行工具的一些簡單操作如下:
1. 顯示根目錄下、文件: ls / 使用 ls 命令來查看當前 ZooKeeper 中所包含的內(nèi)容2. 顯示根目錄下、文件: ls2 / 查看當前節(jié)點數(shù)據(jù)并能看到更新次數(shù)等數(shù)據(jù)3. 創(chuàng)建文件,并設(shè)置初始內(nèi)容: create /zk"test" 創(chuàng)建一個新的 znode節(jié)點“ zk ”以及與它關(guān)聯(lián)的字符串4. 獲取文件內(nèi)容: get /zk 確認 znode 是否包含我們所創(chuàng)建的字符串5. 修改文件內(nèi)容: set /zk"zkbak" 對 zk 所關(guān)聯(lián)的字符串進行設(shè)置6. 刪除文件: delete /zk 將剛才創(chuàng)建的 znode 刪除7. 退出客戶端: quit8. 幫助命令: help
?擴展
通過上述命令實踐,我們可以發(fā)現(xiàn),zookeeper使用了一個類似文件系統(tǒng)的樹結(jié)構(gòu),數(shù)據(jù)可以掛在某個節(jié)點上,可以對這個節(jié)點進行刪改。另外我們還發(fā)現(xiàn),當改動一個節(jié)點的時候,集群中活著的機器都會更新到一致的數(shù)據(jù)。?
zookeeper的數(shù)據(jù)模型
在簡單使用了zookeeper之后,我們發(fā)現(xiàn)其數(shù)據(jù)模型有些像操作系統(tǒng)的文件結(jié)構(gòu),結(jié)構(gòu)如下圖所示

(1)? ???每個節(jié)點在zookeeper中叫做znode,并且其有一個唯一的路徑標識,如/SERVER2節(jié)點的標識就為/APP3/SERVER2
(2)? ???Znode可以有子znode,并且znode里可以存數(shù)據(jù),但是EPHEMERAL類型的節(jié)點不能有子節(jié)點
(3)? ???Znode中的數(shù)據(jù)可以有多個版本,比如某一個路徑下存有多個數(shù)據(jù)版本,那么查詢這個路徑下的數(shù)據(jù)就需要帶上版本。
(4)? ???znode 可以是臨時節(jié)點,一旦創(chuàng)建這個 znode 的客戶端與服務(wù)器失去聯(lián)系,這個 znode 也將自動刪除,Zookeeper 的客戶端和服務(wù)器通信采用長連接方式,每個客戶端和??服務(wù)器通過心跳來保持連接,這個連接狀態(tài)稱為 session,如果 znode 是臨時節(jié)點,這個 session 失效,znode 也就刪除了
(5)? ???znode 的目錄名可以自動編號,如 App1 已經(jīng)存在,再創(chuàng)建的話,將會自動命名為 App2
(6)? ???znode 可以被監(jiān)控,包括這個目錄節(jié)點中存儲的數(shù)據(jù)的修改,子節(jié)點目錄的變化等,一旦變化可以通知設(shè)置監(jiān)控的客戶端,這個功能是zookeeper對于應(yīng)用最重要的特性,通過這個特性可以實現(xiàn)的功能包括配置的集中管理,集群管理,分布式鎖等等。
?選舉流程
當 leader崩潰或者leader失去大多數(shù)的follower,這時候zk進入恢復(fù)模式,恢復(fù)模式需要重新選舉出一個新的leader,讓所有的 Server都恢復(fù)到一個正確的狀態(tài)。Zk的選舉算法有兩種:一種是基于basic paxos實現(xiàn)的,另外一種是基于fast paxos算法實現(xiàn)的。系統(tǒng)默認的選舉算法為fast paxos。
basic paxos流程:
1 .選舉線程由當前Server發(fā)起選舉的線程擔任,其主要功能是對投票結(jié)果進行統(tǒng)計,并選出推薦的Server;
2 .選舉線程首先向所有Server發(fā)起一次詢問(包括自己);
3 .選舉線程收到回復(fù)后,驗證是否是自己發(fā)起的詢問(驗證zxid是否一致),然后獲取對方的id(myid),并存儲到當前詢問對象列表中,最后獲取對方提議的leader相關(guān)信息(id,zxid),并將這些信息存儲到當次選舉的投票記錄表中;
4. 收到所有Server回復(fù)以后,就計算出zxid最大的那個Server,并將這個Server相關(guān)信息設(shè)置成下一次要投票的Server;
5. 線程將當前zxid最大的Server設(shè)置為當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數(shù), 設(shè)置當前推薦的leader為獲勝的Server,將根據(jù)獲勝的Server相關(guān)信息設(shè)置自己的狀態(tài),否則,繼續(xù)這個過程,直到leader被選舉出來。
通 過流程分析我們可以得出:要使Leader獲得多數(shù)Server的支持,則Server總數(shù)必須是奇數(shù)2n+1,且存活的Server的數(shù)目不得少于 n+1.每個Server啟動后都會重復(fù)以上流程。在恢復(fù)模式下,如果是剛從崩潰狀態(tài)恢復(fù)的或者剛啟動的server還會從磁盤快照中恢復(fù)數(shù)據(jù)和會話信 息,zk會記錄事務(wù)日志并定期進行快照,方便在恢復(fù)時進行狀態(tài)恢復(fù)。
應(yīng)用場景
? 是指通過指定的名字來獲取資源或者服務(wù)的地址,提供者的信息。利用Zookeeper很容易創(chuàng)建一個全局的路徑,而這個路徑就可以作為一個名字,它可以指向集群中的集群,提供的服務(wù)的地址,遠程對象等。簡單來說使用Zookeeper做命名服務(wù)就是用路徑作為名字,路徑上的數(shù)據(jù)就是其名字指向的實體。
阿里巴巴集團開源的分布式服務(wù)框架Dubbo中使用ZooKeeper來作為其命名服務(wù),維護全局的服務(wù)地址列表。在Dubbo實現(xiàn)中:
服務(wù)提供者在啟動的時候,向ZK上的指定節(jié)點/dubbo/${serviceName}/providers目錄下寫入自己的URL地址,這個操作就完成了服務(wù)的發(fā)布。
服務(wù)消費者啟動的時候,訂閱/dubbo/{serviceName}/providers目錄下的提供者URL地址, 并向/dubbo/{serviceName} /consumers目錄下寫入自己的URL地址。
注意,所有向ZK上注冊的地址都是臨時節(jié)點,這樣就能夠保證服務(wù)提供者和消費者能夠自動感應(yīng)資源的變化。
另外,Dubbo還有針對服務(wù)粒度的監(jiān)控,方法是訂閱/dubbo/{serviceName}目錄下所有提供者和消費者的信息。
