注:運(yùn)行client是指作為客戶端,與server進(jìn)行數(shù)據(jù)通信,而運(yùn)行server是指將ZK作為服務(wù)器部署運(yùn)行。
1.1.2軟件環(huán)境
ZooKeeper Server需要6或更高版本的JDK支持。集群的機(jī)器數(shù)量方面,建議使用3臺(tái)獨(dú)立的linux服務(wù)器構(gòu)成的一個(gè)ZK集群。需要明確一個(gè)很重要的特性:集群中只要有過半的機(jī)器是正常工作的,那么整個(gè)集群對(duì)外就是可用的
你可以按照以下步驟來配置一個(gè)ZK機(jī)器
1. 安裝JDK。相關(guān)鏈接:http://JAVA.sun.com/javase/downloads/index.jsp
2. 設(shè)置Java heap 大小。避免內(nèi)存與磁盤空間的交換,能夠大大提升ZK的性能,設(shè)置合理的heap大小則能有效避免此類空間交換的觸發(fā)。在正式發(fā)布上線之前,建議是針對(duì)使用場(chǎng)景進(jìn)行一些壓力測(cè)試,確保正常運(yùn)行后內(nèi)存的使用不會(huì)觸發(fā)此類交換。通常在一個(gè)物理內(nèi)存為4G的機(jī)器上,最多設(shè)置-Xmx為3G。
3. 下載安裝ZooKeeper,相關(guān)鏈接:http://zookeeper.Apache.org/releases.html
4. 配置文件zoo.cfg。初次使用zookeeper,按照如下這個(gè)簡單配置即可:
tickTime=2000
dataDir=/var/lib/zookeeper/
clientPort=2181
initLimit=5
syncLimit=2 server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
本文后續(xù)章節(jié)會(huì)對(duì)這些參數(shù)進(jìn)行詳細(xì)的介紹,這里只是簡單說幾點(diǎn):
A. 集群中的每臺(tái)機(jī)器都需要感知整個(gè)集群是由哪幾臺(tái)機(jī)器組成的,在配置文件中,可以按照這樣的格式,每行寫一個(gè)機(jī)器配置:server.id=host:port:port. 關(guān)于這個(gè)id,我們稱之為Server ID,標(biāo)識(shí)host機(jī)器在集群中的機(jī)器序號(hào),在每個(gè)ZK機(jī)器上,我們需要在數(shù)據(jù)目錄(數(shù)據(jù)目錄就是dataDir參數(shù)指定的那個(gè)目錄)下創(chuàng)建一個(gè)myid文件,myid中就是這個(gè)Server ID數(shù)字。
B. 在ZooKeeper的設(shè)計(jì)中,集群中任意一臺(tái)機(jī)器上的zoo.cfg文件的內(nèi)容都是一致的。因此最好是用SVN把這個(gè)文件管理起來,保證每個(gè)機(jī)器都能共享到一份相同的配置。
5. 關(guān)于myid文件。myid文件中只有一個(gè)數(shù)字,即一個(gè)Server ID。例如,server.1 的myid文件內(nèi)容就是"1"。注意,請(qǐng)確保每個(gè)server的myid文件中id數(shù)字不同,并且和server.id=host:port:port中的id一致。另外,id的范圍是1~255。
6. 至此,配置文件基本ok,可以嘗試使用如下命令來啟動(dòng)zookeeper了:
$ java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.quorum.QuorumPeerMainzoo.cfg
注意,不同的ZK版本,依賴的log4j和slf4j版本也是不一樣的,請(qǐng)看清楚自己的版本后,再執(zhí)行上面這個(gè)命令。QuorumPeerMain類會(huì)啟動(dòng)ZooKeeper Server,同時(shí),JMX MB也會(huì)被啟動(dòng),方便管理員在JMX管理控制臺(tái)上進(jìn)行ZK的控制。這里有對(duì)ZK JMX的詳細(xì)介紹:http://zookeeper.apache.org/doc/r3.4.3/zookeeperJMX.html. 另外,完全可以有更簡便的方式,直接使用%ZK_HOME%/bin 中的腳本啟動(dòng)即可。
./zkServer.sh start
7. 連接ZK host來檢驗(yàn)部署是否成功。
A. Java語言的話,可以通過運(yùn)行這個(gè)命令來檢測(cè):
$ java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf:src/java/lib/jline-0.9.94.jar org.apache.zookeeper.ZooKeeperMain -server 127.0.0.1:2181
B. 如果是C語言的話,方法如下:
$ make cli_st
$ make cli_mt
然后按照的這樣的方式連接ZK:$ cli_mt 127.0.0.1:2181 無論運(yùn)行哪種客戶端,最終都是一個(gè)類似于文件系統(tǒng)的命令行操作。
注意:除了上面這種檢測(cè)方法,其實(shí)%ZK_HOME%/bin也有其它腳本,下面這個(gè)命令執(zhí)行后,就進(jìn)入了zookeeper樹狀結(jié)構(gòu)的文件系統(tǒng)中。
./zkCli.sh
另外,還有一種方式,能夠查看ZK服務(wù)器當(dāng)前狀態(tài),如下,這個(gè)能夠很好的看出目前這個(gè)機(jī)器的運(yùn)行情況了:
$ echo stat|nc localhost 2181
Zookeeper version: 3.4.3-1240972, built on 02/06/2012 10:48 GMT
Clients:
/127.0.0.1:40293[0](queued=0,recved=1,sent=0)
Latency min/avg/max: 1/2/3
Received: 4
Sent: 3
Outstanding: 0
Zxid: 0×200000006
Mode: leader
Node count: 4
1.3單機(jī)模式的配置
如果你想安裝一個(gè)ZooKeeper來進(jìn)行開發(fā)測(cè)試,通常可以使用單機(jī)模式來啟動(dòng)ZK。大體的步驟和上面說的是一樣了,除了配置文件會(huì)更加簡單一些。詳細(xì)的配置方法可以查看這里:http://zookeeper.apache.org/doc/r3.4.3/zookeeperStarted.html#sc_InstallingSingleMode
2.運(yùn) 維
2.1 部署方案的設(shè)計(jì)
我們常說的ZooKeeper能夠提供高可用分布式協(xié)調(diào)服務(wù),是要基于以下兩個(gè)條件:
1. 集群中只有少部分的機(jī)器不可用。這里說的不可用是指這些機(jī)器或者是本身down掉了,或者是因?yàn)榫W(wǎng)絡(luò)原因,有一部分機(jī)器無法和集群中其它絕大部分的機(jī)器通信。例如,如果ZK集群是跨機(jī)房部署的,那么有可能一些機(jī)器所在的機(jī)房被隔離了。
2. 正確部署ZK server,有足夠的磁盤存儲(chǔ)空間以及良好的網(wǎng)絡(luò)通信環(huán)境。
下面將會(huì)從集群和單機(jī)兩個(gè)維度來說明,幫助zookeeper管理員盡可能地提高ZK集群的可用性。
2.1.1集群維度
在上面提到的"過半存活即可用"特性中已經(jīng)講到過,整個(gè)集群如果對(duì)外要可用的話,那么集群中必須要有過半的機(jī)器是正常工作并且彼此之間能夠正常通信。基于這個(gè)特性,那么如果想搭建一個(gè)能夠允許F臺(tái)機(jī)器down掉的集群,那么就要部署一個(gè)由2xF+1 臺(tái)機(jī)器構(gòu)成的ZK集群。因此,一個(gè)由3臺(tái)機(jī)器構(gòu)成的ZK集群,能夠在down掉一臺(tái)機(jī)器后依然正常工作,而5臺(tái)機(jī)器的集群,能夠?qū)膳_(tái)機(jī)器down掉的情況容災(zāi)。注意,如果是一個(gè)6臺(tái)機(jī)器構(gòu)成的ZK集群,同樣只能夠down掉兩臺(tái)機(jī)器,因?yàn)槿绻鹍own掉3臺(tái),剩下的機(jī)器就沒有過半了。基于這個(gè)原因,ZK集群通常設(shè)計(jì)部署成奇數(shù)臺(tái)機(jī)器。
所以,為了盡可能地提高ZK集群的可用性,應(yīng)該盡量避免一大批機(jī)器同時(shí)down掉的風(fēng)險(xiǎn),換句話說,最好能夠?yàn)槊颗_(tái)機(jī)器配置互相獨(dú)立的硬件環(huán)境。舉個(gè)例子,如果大部分的機(jī)器都掛在同一個(gè)交換機(jī)上,那么這個(gè)交換機(jī)一旦出現(xiàn)問題,將會(huì)對(duì)整個(gè)集群的服務(wù)造成嚴(yán)重的影響。其它類似的還有諸如:供電線路,散熱系統(tǒng)等。其實(shí)在真正的實(shí)踐過程中,如果條件允許,通常都建議嘗試跨機(jī)房部署。畢竟多個(gè)機(jī)房同時(shí)發(fā)生故障的機(jī)率還是挺小的。
2.1.2 單機(jī)維度
對(duì)于ZK來說,如果在運(yùn)行過程中,需要和其它應(yīng)用程序來競(jìng)爭磁盤,CPU,網(wǎng)絡(luò)或是內(nèi)存資源的話,那么整體性能將會(huì)大打折扣。
首先來看看磁盤對(duì)于ZK性能的影響。客戶端對(duì)ZK的更新操作都是永久的,不可回退的,也就是說,一旦客戶端收到一個(gè)來自server操作成功的響應(yīng),那么這個(gè)變更就永久生效了。為做到這點(diǎn),ZK會(huì)將每次更新操作以事務(wù)日志的形式寫入磁盤,寫入成功后才會(huì)給予客戶端響應(yīng)。明白這點(diǎn)之后,你就會(huì)明白磁盤的吞吐性能對(duì)于ZK的影響了,磁盤寫入速度制約著ZK每個(gè)更新操作的響應(yīng)。為了盡量減少ZK在讀寫磁盤上的性能損失,不仿試試下面說的幾點(diǎn):
A、使用單獨(dú)的磁盤作為事務(wù)日志的輸出(比如我們這里的ZK集群,使用單獨(dú)的掛載點(diǎn)用于事務(wù)日志的輸出)。事務(wù)日志的寫性能確實(shí)對(duì)ZK性能,尤其是更新操作的性能影響很大,所以想辦法搞到一個(gè)單獨(dú)的磁盤吧!ZK的事務(wù)日志輸出是一個(gè)順序?qū)懳募倪^程,本身性能是很高的,所以盡量保證不要和其它隨機(jī)寫的應(yīng)用程序共享一塊磁盤,盡量避免對(duì)磁盤的競(jìng)爭。
B、盡量避免內(nèi)存與磁盤空間的交換。如果希望ZK能夠提供完全實(shí)時(shí)的服務(wù)的話,那么基本是不允許操作系統(tǒng)觸發(fā)此類swap的。因此在分配JVM堆大小的時(shí)候一定要非常小心,具體在本文最后的"注意事項(xiàng)"章節(jié)中有講到。
2.2.1 清理數(shù)據(jù)目錄
上文中提到dataDir目錄指定了ZK的數(shù)據(jù)目錄,用于存儲(chǔ)ZK的快照文件(snapshot)。另外,默認(rèn)情況下,ZK的事務(wù)日志也會(huì)存儲(chǔ)在這個(gè)目錄中。在完成若干次事務(wù)日志之后(在ZK中,凡是對(duì)數(shù)據(jù)有更新的操作,比如創(chuàng)建節(jié)點(diǎn),刪除節(jié)點(diǎn)或是對(duì)節(jié)點(diǎn)數(shù)據(jù)內(nèi)容進(jìn)行更新等,都會(huì)記錄事務(wù)日志),ZK會(huì)觸發(fā)一次快照(snapshot),將當(dāng)前server上所有節(jié)點(diǎn)的狀態(tài)以快照文件的形式dump到磁盤上去,即snapshot文件。這里的若干次事務(wù)日志是可以配置的,默認(rèn)是100000,具體參看下文中關(guān)于配置參數(shù)"snapCount"的介紹。
考慮到ZK運(yùn)行環(huán)境的差異性,以及對(duì)于這些歷史文件,不同的管理員可能有自己的用途(例如作為數(shù)據(jù)備份),因此默認(rèn)ZK是不會(huì)自動(dòng)清理快照和事務(wù)日志,需要交給管理員自己來處理。這里是我們用的清理方法,保留最新的66個(gè)文件,將它寫到crontab中,每天凌晨2點(diǎn)觸發(fā)一次:
#!/bin/bash
#snapshot file dir
dataDir=/home/yinshi.nc/test/zk_data/version-2
#tran log dir
dataLogDir=/home/yinshi.nc/test/zk_log/version-2
#zk log dir
logDir=/home/yinshi.nc/test/logs
#Leave 66 files
count=66
count=$[$count+1]
ls -t $dataLogDir/log.* | tail -n +$count | xargs rm -f
ls -t $dataDir/snapshot.* | tail -n +$count | xargs rm -f
ls -t $logDir/zookeeper.log.* | tail -n +$count | xargs rm -f
#find /home/yinshi.nc/taokeeper/zk_data/version-2 -name "snap*" -mtime +1 | xargs rm -f
#find /home/yinshi.nc/taokeeper/zk_logs/version-2 -name "log*" -mtime +1 | xargs rm -f
#find /home/yinshi.nc/taokeeper/logs/ -name "zookeeper.log.*" -mtime +1 | xargs rm –f
其實(shí),僅管ZK沒有自動(dòng)幫我們清理歷史文件,但是它的還是提供了一個(gè)叫PurgeTxnLog的 工具類,實(shí)現(xiàn)了一種簡單的歷史文件清理策略,可以在這里看一下他的使用方法:http://zookeeper.apache.org/doc/r3.4.3/api/index.html 簡單使用如下:
java -cp zookeeper.jar:lib/slf4j-api-1.6.1.jar:lib/slf4j-log4j12-1.6.1.jar:lib/log4j-1.2.15.jar:conf org.apache.zookeeper.server.PurgeTxnLog<dataDir><snapDir> -n <count>
最后一個(gè)參數(shù)表示希望保留的歷史文件個(gè)數(shù),注意,count必須是大于3的整數(shù)。可以把這句命令寫成一個(gè)定時(shí)任務(wù),以便每天定時(shí)執(zhí)行清理。
注意: 從3.4.0版本開始, zookeeper提供了自己清理歷史文件的功能了,相關(guān)的配置參數(shù)是autopurge.snapRetainCount和autopurge.purgeInterval,在本文后面會(huì)具體說明。更多關(guān)于zookeeper的日志清理,可以閱讀這個(gè)文章《https://blog.51cto.com/nileader/932156》。
2.2.2 ZK程序日志
這里說兩點(diǎn),ZK默認(rèn)是沒有向ROLLINGFILE文件輸出程序運(yùn)行時(shí)日志的,需要我們自己在conf/log4j.properties中配置日志路徑。另外,沒有特殊要求的話,日志級(jí)別設(shè)置為INFO或以上,我曾經(jīng)測(cè)試過,日志級(jí)別設(shè)置為DEBUG的話,性能影響很大!
2.3 Server的自檢恢復(fù)
ZK運(yùn)行過程中,如果出現(xiàn)一些無法處理的異常,會(huì)直接退出進(jìn)程,也就是所謂的快速失敗(fail fast)模式。在上文中有提到,"過半存活即可用"的特性使得集群中少數(shù)機(jī)器down掉后,整個(gè)集群還是可以對(duì)外正常提供服務(wù)的。另外,這些down掉的機(jī)器重啟之后,能夠自動(dòng)加入到集群中,并且自動(dòng)和集群中其它機(jī)器進(jìn)行狀態(tài)同步(主要就是從Leader那里同步最新的數(shù)據(jù)),從而達(dá)到自我恢復(fù)的目的。
因此,我們很容易就可以想到,是否可以借助一些工具來自動(dòng)完成機(jī)器的狀態(tài)檢測(cè)與重啟工作。回答是肯定的,這里推薦兩個(gè)工具: Daemontools(http://cr.yp.to/daemontools.html) 和 SMF(http://en.wikipedia.org/wiki/Service_Management_Facility),能夠幫助你監(jiān)控ZK進(jìn)程,一旦進(jìn)程退出后,能夠自動(dòng)重啟進(jìn)程,從而使down掉的機(jī)器能夠重新加入到集群中去~
2.4 監(jiān)控
有幾種方法:
1、 ZK提供一些簡單但是功能強(qiáng)大的4字命令,通過對(duì)這些4字命令的返回內(nèi)容進(jìn)行解析,可以獲取不少關(guān)于ZK運(yùn)行時(shí)的信息。
2、用jmx也能夠獲取一些運(yùn)行時(shí)信息,詳細(xì)可以查看這里:http://zookeeper.apache.org/doc/r3.4.3/zookeeperJMX.html
3、我的老東家阿里巴巴已經(jīng)實(shí)現(xiàn)的一個(gè)ZooKeeper監(jiān)控——TaoKeeper,已開源,在這里:https://github.com/alibaba/taokeeper
,主要功能如下:
A、機(jī)器CPU/MEM/LOAD的監(jiān)控
B、ZK日志目錄所在磁盤空間監(jiān)控
C、單機(jī)連接數(shù)的峰值報(bào)警
D、單機(jī)Watcher數(shù)的峰值報(bào)警
E、節(jié)點(diǎn)自檢
F、ZK運(yùn)行時(shí)信息展示
2.5 日志管理
ZK使用log4j作為日志系統(tǒng),conf目錄中有一份默認(rèn)的log4j配置文件,注意,這個(gè)配置文件中還沒有開啟ROLLINGFILE文件輸出,配置下即可。其它關(guān)于log4j的詳細(xì)介紹,可以移步到log4j的官網(wǎng):http://logging.apache.org/log4j/1.2/manual.html#defaultInit
2.6加載數(shù)據(jù)出錯(cuò)
ZK在啟動(dòng)的過程中,首先會(huì)根據(jù)事務(wù)日志中的事務(wù)日志記錄,從本地磁盤加載最后一次提交時(shí)候的快照數(shù)據(jù),如果讀取事務(wù)日志出錯(cuò)或是其它問題(通常在日志中可以看到一些IO異常),將導(dǎo)致server將無法啟動(dòng)。碰到類似于這種數(shù)據(jù)文件出錯(cuò)導(dǎo)致無法啟動(dòng)服務(wù)器的情況,一般按照如下順序來恢復(fù):
1、確認(rèn)集群中其它機(jī)器是否正常工作,方法是使用"stat"這個(gè)命令來檢查:echo stat|nc ip 2181
2、如果確認(rèn)其它機(jī)器是正常工作的(這里要說明下,所謂正常工作還是指集群中有過半機(jī)器可用),那么可以開始刪除本機(jī)的一些數(shù)據(jù)了,刪除$dataDir/version-2和$dataLogDir/version-2 兩個(gè)目錄下的所有文件。
重啟server。重啟之后,這個(gè)機(jī)器就會(huì)從Leader那里同步到最新數(shù)據(jù),然后重新加入到集群中提供服務(wù)。
2.7 配置參數(shù)詳解(主要是%ZOOKEEPER_HOME%/conf/zoo.cfg文件)
參數(shù)名
說明
clientPort # 客戶端連接server的端口,即對(duì)外服務(wù)端口,一般設(shè)置為2181吧。
dataDir # 存儲(chǔ)快照文件snapshot的目錄。默認(rèn)情況下,事務(wù)日志也會(huì)存儲(chǔ)在這里。建議同時(shí)配置參數(shù)dataLogDir, 事務(wù)日志的寫性能直接影響zk性能。
tickTime # ZK中的一個(gè)時(shí)間單元。ZK中所有時(shí)間都是以這個(gè)時(shí)間單元為基礎(chǔ),進(jìn)行整數(shù)倍配置的。例如,session的最小超時(shí)時(shí)間是2*tickTime。
dataLogDir # 事務(wù)日志輸出目錄。盡量給事務(wù)日志的輸出配置單獨(dú)的磁盤或是掛載點(diǎn),這將極大的提升ZK性能。 (No Java system property)
globalOutstandingLimit # 最大請(qǐng)求堆積數(shù)。默認(rèn)是1000。ZK運(yùn)行的時(shí)候, 盡管server已經(jīng)沒有空閑來處理更多的客戶端請(qǐng)求了,但是還是允許客戶端將請(qǐng)求提交到服務(wù)器上來,以提高吞吐性能。當(dāng)然,為了防止Server內(nèi)存溢出,這個(gè)請(qǐng)求堆積數(shù)還是需要限制下的。 (Java system property:?zookeeper.globalOutstandingLimit.)
preAllocSize # 預(yù)先開辟磁盤空間,用于后續(xù)寫入事務(wù)日志。默認(rèn)是64M,每個(gè)事務(wù)日志大小就是64M。如果ZK的快照頻率較大的話,建議適當(dāng)減小這個(gè)參數(shù)。(Java system property:zookeeper.preAllocSize)
snapCount # 每進(jìn)行snapCount次事務(wù)日志輸出后,觸發(fā)一次快照(snapshot), 此時(shí),ZK會(huì)生成一個(gè)snapshot.*文件,同時(shí)創(chuàng)建一個(gè)新的事務(wù)日志文件log.*。默認(rèn)是100000.(真正的代碼實(shí)現(xiàn)中,會(huì)進(jìn)行一定的隨機(jī)數(shù)處理,以避免所有服務(wù)器在同一時(shí)間進(jìn)行快照而影響性能)(Java system property:zookeeper.snapCount)
traceFile # 用于記錄所有請(qǐng)求的log,一般調(diào)試過程中可以使用,但是生產(chǎn)環(huán)境不建議使用,會(huì)嚴(yán)重影響性能。(Java system property:requestTraceFile)
maxClientCnxns # 單個(gè)客戶端與單臺(tái)服務(wù)器之間的連接數(shù)的限制,是ip級(jí)別的,默認(rèn)是60,如果設(shè)置為0,那么表明不作任何限制。請(qǐng)注意這個(gè)限制的使用范圍,僅僅是單臺(tái)客戶端機(jī)器與單臺(tái)ZK服務(wù)器之間的連接數(shù)限制,不是針對(duì)指定客戶端IP,也不是ZK集群的連接數(shù)限制,也不是單臺(tái)ZK對(duì)所有客戶端的連接數(shù)限制。指定客戶端IP的限制策略,這里有一個(gè)patch,可以嘗試一下:http://rdc.taobao.com/team/jm/archives/1334(No Java system property)
clientPortAddress # 對(duì)于多網(wǎng)卡的機(jī)器,可以為每個(gè)IP指定不同的監(jiān)聽端口。默認(rèn)情況是所有IP都監(jiān)聽clientPort指定的端口。New in 3.3.0
minSessionTimeoutmaxSessionTimeout # Session超時(shí)時(shí)間限制,如果客戶端設(shè)置的超時(shí)時(shí)間不在這個(gè)范圍,那么會(huì)被強(qiáng)制設(shè)置為最大或最小時(shí)間。默認(rèn)的Session超時(shí)時(shí)間是在2 *tickTime ~ 20 * tickTime這個(gè)范圍 New in 3.3.0
fsync.warningthresholdms # 事務(wù)日志輸出時(shí),如果調(diào)用fsync方法超過指定的超時(shí)時(shí)間,那么會(huì)在日志中輸出警告信息。默認(rèn)是1000ms。(Java system property:fsync.warningthresholdms) New in 3.3.4
autopurge.purgeInterval # 在上文中已經(jīng)提到,3.4.0及之后版本,ZK提供了自動(dòng)清理事務(wù)日志和快照文件的功能,這個(gè)參數(shù)指定了清理頻率,單位是小時(shí),需要配置一個(gè)1或更大的整數(shù),默認(rèn)是0,表示不開啟自動(dòng)清理功能。(No Java system property) New in 3.4.0
autopurge.snapRetainCount # 這個(gè)參數(shù)和上面的參數(shù)搭配使用,這個(gè)參數(shù)指定了需要保留的文件數(shù)目。默認(rèn)是保留3個(gè)。(No Java system property) New in 3.4.0
electionAlg # 在之前的版本中, 這個(gè)參數(shù)配置是允許我們選擇leader選舉算法,但是由于在以后的版本中,只會(huì)留下一種"TCP-based version of fast leader election"算法,所以這個(gè)參數(shù)目前看來沒有用了,這里也不詳細(xì)展開說了。(No Java system property)
initLimit # Follower在啟動(dòng)過程中,會(huì)從Leader同步所有最新數(shù)據(jù),然后確定自己能夠?qū)ν夥?wù)的起始狀態(tài)。Leader允許F在initLimit時(shí)間內(nèi)完成這個(gè)工作。通常情況下,我們不用太在意這個(gè)參數(shù)的設(shè)置。如果ZK集群的數(shù)據(jù)量確實(shí)很大了,F(xiàn)在啟動(dòng)的時(shí)候,從Leader上同步數(shù)據(jù)的時(shí)間也會(huì)相應(yīng)變長,因此在這種情況下,有必要適當(dāng)調(diào)大這個(gè)參數(shù)了。(No Java system property)
syncLimit # 在運(yùn)行過程中,Leader負(fù)責(zé)與ZK集群中所有機(jī)器進(jìn)行通信,例如通過一些心跳檢測(cè)機(jī)制,來檢測(cè)機(jī)器的存活狀態(tài)。如果L發(fā)出心跳包在syncLimit之后,還沒有從F那里收到響應(yīng),那么就認(rèn)為這個(gè)F已經(jīng)不在線了。注意:不要把這個(gè)參數(shù)設(shè)置得過大,否則可能會(huì)掩蓋一些問題。(No Java system property)
leaderServes # 默認(rèn)情況下,Leader是會(huì)接受客戶端連接,并提供正常的讀寫服務(wù)。但是,如果你想讓Leader專注于集群中機(jī)器的協(xié)調(diào),那么可以將這個(gè)參數(shù)設(shè)置為no,這樣一來,會(huì)大大提高寫操作的性能。(Java system property: zookeeper.leaderServes)。
server.x=[hostname]:nnnnn[:nnnnn] # 這里的x是一個(gè)數(shù)字,與myid文件中的id是一致的。右邊可以配置兩個(gè)端口,第一個(gè)端口用于F和L之間的數(shù)據(jù)同步和其它通信,第二個(gè)端口用于Leader選舉過程中投票通信。 (No Java system property)
group.x=nnnnn[:nnnnn]weight.x=nnnnn # 對(duì)機(jī)器分組和權(quán)重設(shè)置,可以 參見這里(No Java system property)
cnxTimeout # Leader選舉過程中,打開一次連接的超時(shí)時(shí)間,默認(rèn)是5s。(Java system property: zookeeper.cnxTimeout)
zookeeper.DigestAuthenticationProvider .superDigest # ZK權(quán)限設(shè)置相關(guān),具體參見《使用super身份對(duì)有權(quán)限的節(jié)點(diǎn)進(jìn)行操作》 和 《ZooKeeper權(quán)限控制》
skipACL # 對(duì)所有客戶端請(qǐng)求都不作ACL檢查。如果之前節(jié)點(diǎn)上設(shè)置有權(quán)限限制,一旦服務(wù)器上打開這個(gè)開頭,那么也將失效。(Java system property:zookeeper.skipACL)
forceSync # 這個(gè)參數(shù)確定了是否需要在事務(wù)日志提交的時(shí)候調(diào)用FileChannel.force來保證數(shù)據(jù)完全同步到磁盤。(Java system property:zookeeper.forceSync)
jute.maxbuffer # 每個(gè)節(jié)點(diǎn)最大數(shù)據(jù)量,是默認(rèn)是1M。這個(gè)限制必須在server和client端都進(jìn)行設(shè)置才會(huì)生效。(Java system property:jute.maxbuffer)
2.8 常用的四字命令
conf # 輸出server的詳細(xì)配置信息。New in 3.3.0
$>echo conf|nc localhost 2181
clientPort=2181
dataDir=/home/test/taokeeper/zk_data/version-2
dataLogDir=/test/admin/taokeeper/zk_log/version-2
tickTime=2000
maxClientCnxns=1000
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=2
initLimit=10
syncLimit=5
electionAlg=3
electionPort=3888
quorumPort=2888
peerType=0
cons # 輸出指定server上所有客戶端連接的詳細(xì)信息,包括客戶端IP,會(huì)話ID等。 New in 3.3.0類似于這樣的信息:
$>echo cons|nc localhost 2181
/1.2.3.4:43527[1](queued=0,recved=152802,
sent=152806,sid=0x2389e662b98c424,lop=PING,
est=1350385542196,to=6000,
lcxid=0×114,lzxid=0xffffffffffffffff,lresp=1350690663308,llat=0,minlat=0,avglat=0,maxlat=483)
……
crst # 功能性命令。重置所有連接的統(tǒng)計(jì)信息。New in 3.3.0
dump # 這個(gè)命令針對(duì)Leader執(zhí)行,用于輸出所有等待隊(duì)列中的會(huì)話和臨時(shí)節(jié)點(diǎn)的信息。
envi # 用于輸出server的環(huán)境變量。包括操作系統(tǒng)環(huán)境和Java環(huán)境。
ruok # 用于測(cè)試server是否處于無錯(cuò)狀態(tài)。如果正常,則返回"imok",否則沒有任何響應(yīng)。 注意:ruok不是一個(gè)特別有用的命令,它不能反映一個(gè)server是否處于正常工作。"stat"命令更靠譜。
stat # 輸出server簡要狀態(tài)和連接的客戶端信息。
srvr # 和stat類似,New in 3.3.0
$>echo stat|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Clients:
/10.2.3.4:59179[1](queued=0,recved=44845,sent=44845)
Latency min/avg/max: 0/0/1036
Received: 2274602238
Sent: 2277795620
Outstanding: 0
Zxid: 0xa1b3503dd
Mode: leader
Node count: 37473
$>echo srvr|nc localhost 2181
Zookeeper version: 3.3.5-1301095, built on 03/15/2012 19:48 GMT
Latency min/avg/max: 0/0/980
Received: 2592698547
Sent: 2597713974
Outstanding: 0
Zxid: 0xa1b356b5b
Mode: follower
Node count: 37473
srst # 重置server的統(tǒng)計(jì)信息。
wchs # 列出所有watcher信息概要信息,數(shù)量等:New in 3.3.0
$>echo wchs|nc localhost 2181
3890 connections watching 537 paths
Total watches:6909
wchc # 列出所有watcher信息,以watcher的session為歸組單元排列,列出該會(huì)話訂閱了哪些path:New in 3.3.0
$>echo wchc|nc localhost 2181
0x2389e662b97917f
/mytest/test/path1/node1
0x3389e65c83cd790
/mytest/test/path1/node2
0x1389e65c7ef6313
/mytest/test/path1/node3
/mytest/test/path1/node1
wchp # 列出所有watcher信息,以watcher的path為歸組單元排列,列出該path被哪些會(huì)話訂閱著:New in 3.3.0
$>echo wchp|nc localhost 2181
/mytest/test/path1/node
0x1389e65c7eea4f5
0x1389e65c7ee2f68
/mytest/test/path1/node2
0x2389e662b967c29
/mytest/test/path1/node3
0x3389e65c83dd2e0
0x1389e65c7f0c37c
0x1389e65c7f0c364
注意,wchc和wchp這兩個(gè)命令執(zhí)行的輸出結(jié)果都是針對(duì)session的,對(duì)于運(yùn)維人員來說可視化效果并不理想,可以嘗試將cons命令執(zhí)行輸出的信息整合起來,就可以用客戶端IP來代替會(huì)話ID了,具體可以看這個(gè)實(shí)現(xiàn):http://rdc.taobao.com/team/jm/archives/1450
mntr
輸出一些ZK運(yùn)行時(shí)信息,通過對(duì)這些返回結(jié)果的解析,可以達(dá)到監(jiān)控的效果。New in 3.4.0
$ echo mntr | nc localhost 2185
zk_version 3.4.0
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 70
zk_packets_sent 69
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 4
zk_watch_count 0
zk_ephemerals_count 0
zk_Approximate_data_size 27
zk_followers 4 – only exposed by the Leader
zk_synced_followers 4 – only exposed by the Leader
zk_pending_syncs 0 – only exposed by the Leader
zk_open_file_descriptor_count 23 – only available on Unix platforms
zk_max_file_descriptor_count 1024 – only available on Unix platforms
2.9 數(shù)據(jù)文件管理
默認(rèn)情況下,ZK的數(shù)據(jù)文件和事務(wù)日志是保存在同一個(gè)目錄中,建議是將事務(wù)日志存儲(chǔ)到單獨(dú)的磁盤上。
2.9.1數(shù)據(jù)目錄
ZK的數(shù)據(jù)目錄包含兩類文件:
A、myid – 這個(gè)文件只包含一個(gè)數(shù)字,和server id對(duì)應(yīng)。
B、snapshot. - 按zxid先后順序的生成的數(shù)據(jù)快照。
集群中的每臺(tái)ZK server都會(huì)有一個(gè)用于惟一標(biāo)識(shí)自己的id,有兩個(gè)地方會(huì)使用到這個(gè)id:myid文件和zoo.cfg文件中。myid文件存儲(chǔ)在dataDir目錄中,指定了當(dāng)前server的server id。在zoo.cfg文件中,根據(jù)server id,配置了每個(gè)server的ip和相應(yīng)端口。Zookeeper啟動(dòng)的時(shí)候,讀取myid文件中的server id,然后去zoo.cfg 中查找對(duì)應(yīng)的配置。
zookeeper在進(jìn)行數(shù)據(jù)快照過程中,會(huì)生成 snapshot文件,存儲(chǔ)在dataDir目錄中。文件后綴是zxid,也就是事務(wù)id。(這個(gè)zxid代表了zk觸發(fā)快照那個(gè)瞬間,提交的最后一個(gè)事務(wù)id)。注意,一個(gè)快照文件中的數(shù)據(jù)內(nèi)容和提交第zxid個(gè)事務(wù)時(shí)內(nèi)存中數(shù)據(jù)近似相同。僅管如此,由于更新操作的冪等性,ZK還是能夠從快照文件中恢復(fù)數(shù)據(jù)。數(shù)據(jù)恢復(fù)過程中,將事務(wù)日志和快照文件中的數(shù)據(jù)對(duì)應(yīng)起來,就能夠恢復(fù)最后一次更新后的數(shù)據(jù)了。
2.9.2事務(wù)日志目錄
dataLogDir目錄是ZK的事務(wù)日志目錄,包含了所有ZK的事務(wù)日志。正常運(yùn)行過程中,針對(duì)所有更新操作,在返回客戶端"更新成功"的響應(yīng)前,ZK會(huì)確保已經(jīng)將本次更新操作的事務(wù)日志寫到磁盤上,只有這樣,整個(gè)更新操作才會(huì)生效。每觸發(fā)一次數(shù)據(jù)快照,就會(huì)生成一個(gè)新的事務(wù)日志。事務(wù)日志的文件名是log.,zxid是寫入這個(gè)文件的第一個(gè)事務(wù)id。
2.9.3文件管理
不同的zookeeper server生成的snapshot文件和事務(wù)日志文件的格式都是一致的(無論是什么環(huán)境,或是什么樣的zoo.cfg 配置)。因此,如果某一天生產(chǎn)環(huán)境中出現(xiàn)一些古怪的問題,你就可以把這些文件下載到開發(fā)環(huán)境的zookeeper中加載起來,便于調(diào)試發(fā)現(xiàn)問題,而不會(huì)影響生產(chǎn)運(yùn)行。另外,使用這些較舊的snapshot和事務(wù)日志,我們還能夠方便的讓ZK回滾到一個(gè)歷史狀態(tài)。
另外,ZK提供的工具類LogFormatter能夠幫助可視化ZK的事務(wù)日志,幫助我們排查問題,關(guān)于事務(wù)日志的可以化,請(qǐng)查看這個(gè)文章《http://f.dataguru.cn/thread-589796-1-1.html》.
需要注意的一點(diǎn)是,zookeeper在運(yùn)行過程中,不斷地生成snapshot文件和事務(wù)日志,但是不會(huì)自動(dòng)清理它們,需要管理員來處理。(ZK本身只需要使用最新的snapshot和事務(wù)日志即可)關(guān)于如何清理文件,上面章節(jié)"日常運(yùn)維"有提到。
2.10 注意事項(xiàng)
2.10.1 保持Server地址列表一致
A、客戶端使用的server地址列表必須和集群所有server的地址列表一致。(如果客戶端配置了集群機(jī)器列表的子集的話,也是沒有問題的,只是少了客戶端的容災(zāi)。)
B、集群中每個(gè)server的zoo.cfg中配置機(jī)器列表必須一致。
2.10.2 獨(dú)立的事務(wù)日志輸出
對(duì)于每個(gè)更新操作,ZK都會(huì)在確保事務(wù)日志已經(jīng)落盤后,才會(huì)返回客戶端響應(yīng)。因此事務(wù)日志的輸出性能在很大程度上影響ZK的整體吞吐性能。強(qiáng)烈建議是給事務(wù)日志的輸出分配一個(gè)單獨(dú)的磁盤。
2.10.3 配置合理的JVM堆大小
確保設(shè)置一個(gè)合理的JVM堆大小,如果設(shè)置太大,會(huì)讓內(nèi)存與磁盤進(jìn)行交換,這將使ZK的性能大打折扣。例如一個(gè)4G內(nèi)存的機(jī)器的,如果你把JVM的堆大小設(shè)置為4G或更大,那么會(huì)使頻繁發(fā)生內(nèi)存與磁盤空間的交換,通常設(shè)置成3G就可以了。當(dāng)然,為了獲得一個(gè)最好的堆大小值,在特定的使用場(chǎng)景下進(jìn)行一些壓力測(cè)試。