一、前言
ZooKeeper
的功能特性通過ZooKeeper
配置文件來進行控制管理( zoo.cfg
配置文件)。 ZooKeeper這樣的設計其實是有它自身的原因的。通過前面對ZooKeeper
的配置可以看出,對ZooKeeper
集群進行配置的時候,它的配置文檔是完全相同的(對於集群偽分布模式來說,只有很少的部分是不同的)。這樣的配置方使得在部署ZooKeeper
服務的時候非常地方便。另外,如果服務器使用不同的配置文件,必須要確保不同配置文件中的服務器列表相匹配。
在設置ZooKeeper
配置文檔的時候,某些參數是可選的,但是某些參數是必須的。這些必須的參數就構成了ZooKeeper
配置文檔的最低配置要求。
最近發現在用zookeeper出現經常出現連接超時,出現連接中斷,數據丟失等原因。后面看了官網配置自己整理優化幾點:
2.1錯誤日志: 2016-04-11 15:00:58,981 [myid:] - WARN [SyncThread:0:FileTxnLog@334] - fsync-ing the write ahead log in SyncThread:0 took 13973ms which will adversely effect operation latency. See the ZooKeeper troubleshooting guide >2.2,錯誤原因分析 “FOLLOWER”在跟“LEADER”同步時,fsync操作時間過長,導致超時。 第一步:分析服務器問題: 我查看了服務器io和負載都不高。內存空間實際使用率不高。可是編輯文件出現了卡頓. 可以發現: 服務器並沒有占用很多內存的進程; 服務器也沒有存在很多的進程; cat /var/log/message查看系統日志並沒有發現什么異常; 另外ping服務器只有0.1ms多的延遲,因此不是網絡問題。 后面發現硬盤有故障重新更換了一塊硬盤。或者更換服務器。 >2.3,錯誤解決 增加“tickTime”或者“initLimit和syncLimit”的值,或者兩者都增大。 >2.4,其他 這個錯誤在上線“使用ZooKeeper獲取地址方案”之前也存在,只不過過沒有這么高頻率,而上線了“ZooKeeper獲取地址方案”之后,ZooKeeper Server之間的同步數據量增大,ZooKeeper Server的負載加重,因而最終導致高頻率出現上述錯誤。
二、配置文件:
下面是在最低配置要求中必須配置的參數:
### 最小配置 最小配置意味着所有的配置文件中必須要包含這些配置選項。 #### clientPort 服務器監聽客戶端連接的端口,亦即客戶端嘗試連接到服務器上的指定端口。 ##### dataDir ZooKeeper存儲內存數據庫快照文件的路徑,並且如果沒有指定其它路徑的話,數據庫更新的事務日志也將存儲到該路徑下。 注意:事務日志會影響ZooKeeper服務器的整體性能,所以建議將事務日志放置到由dataLogDir參數指定的路徑下。 ##### tickTime 單個tick的時間長度,它是ZooKeeper中使用的基本時間單元,以毫秒為單位。它用來調節心跳和超時時間。例如,最小會話超時時間是2個tick。
生產環境例子:
tickTime:CS通信心跳數 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。tickTime以毫秒為單位。 tickTime=2000 initLimit:LF初始通信時限 集群中的follower服務器(F)與leader服務器(L)之間初始連接時能容忍的最多心跳數(tickTime的數量)。 initLimit=5 syncLimit:LF同步通信時限 集群中的follower服務器與leader服務器之間請求和應答之間能容忍的最多心跳數(tickTime的數量)。 syncLimit=2 dataDir:數據文件目錄 Zookeeper保存數據的目錄,默認情況下,Zookeeper將寫數據的日志文件也保存在這個目錄里。 dataDir=/home/michael/opt/zookeeper/data dataLogDir:日志文件目錄 Zookeeper保存日志文件的目錄。 dataLogDir=/home/michael/opt/zookeeper/log clientPort:客戶端連接端口 客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。 clientPort=2333 服務器名稱與地址:集群信息(服務器編號,服務器地址,LF通信端口,選舉端口) 這個配置項的書寫格式比較特殊,規則如下: server.N=YYY:A:B 其中N表示服務器編號,YYY表示服務器的IP地址,A為LF通信端口,表示該服務器與集群中的Leader交換的信息的端口。B為選舉端口,表示選舉新Leader時服務器間相互通信的端口(當Leader掛掉時,其余服務器會相互通信,選擇出新的Leader)。一般來說,集群中每個服務器的A端口都是一樣,每個服務器的B端口也是一樣。但是當所采用的為偽集群時,IP地址都一樣,只能時A端口和B端口不一樣。 #下面是一個非偽集群的例子: server.0=233.34.9.144:2008:6008 server.1=233.34.9.145:2008:6008 server.2=233.34.9.146:2008:6008 server.3=233.34.9.147:2008:6008 #下面是一個偽集群的例子: server.0=127.0.0.1:2008:6008 server.1=127.0.0.1:2007:6007 server.2=127.0.0.1:2006:6006 server.3=127.0.0.1:2005:6005
三、高級配置項說明
本節的配置選項是可選的。你可以使用它們進一步的優化ZooKeeper服務器的行為。有些可以使用Java系統屬性來設置,一般的格式是“zookeeper.keyword”。如果有具體的系統屬性,會在配置選項下面標注出來。
說明:設置Java系統屬性可以在啟動時后面加“-D”參數,比如:-Dzookeeper.keyword=xxx。而這些配置項默認可以通過$ZOOKEEPER_HOME/conf/zoo.cfg進行配置。
dataLogDir
沒有對應的Java系統屬性。
該參數用於配置ZooKeeper服務器存儲事務日志文件的路徑,ZooKeeper默認將事務日志文件和數據快照存儲在同一個目錄下,應盡量將它們分開存儲。
注意:將事務日志文件存儲到一個專門的日志設備上對於服務器的吞吐量和穩定的延遲有很大的影響。事務日志對磁盤性能要求比較高,為了保證數據一致性,ZooKeeper 在響應客戶端事務請求之前,需要將請求的事務日志寫到磁盤上,所以事務日志的寫入性能直接影響ZooKeeper服務器處理請求的吞吐。所以建議給事務日志的輸出配置一個單獨的磁盤或者掛載點。
globalOutstandingLimit
對應的Java系統屬性:zookeeper.globalOutstandingLimit。
客戶端提交請求的速度可能比ZooKeeper處理的速度快得多,特別是當客戶端的數量非常多的時候。為了防止ZooKeeper因為排隊的請求而耗盡內存,ZooKeeper將會對客戶端進行限流,即限制系統中未處理的請求數量不超過globalOutstandingLimit設置的值。默認的限制是 1000。
preAllocSize
對應的Java系統屬性:zookeeper.preAllocSize。
用於配置ZooKeeper事務日志文件預分配的磁盤空間大小。默認的塊大小是64M。改變塊大小的其中一個原因是當數據快照文件生成比較頻繁時可以適當減少塊大小。比如 1000次事務會新產生一個快照(參數為snapCount),新產生快照后會用新的事務日志文件,假設一個事務信息大小100b,那么事務日志預分配的磁盤空間大小為100kb會比較好。
snapCount
對應的Java系統屬性:zookeeper.snapCount。
ZooKeeper 將事務記錄到事務日志中。當 snapCount 個事務被寫到一個日志文件后,啟動一個快照並創建一個新的事務日志文件。snapCount 的默認值是 100,000。
traceFile
對應的Java系統屬性:requestTraceFile。
如果定義了該選項,那么請求將會記錄到一個名為traceFile.year.month.day的跟蹤文件中。使用該選項可以提供很有用的調試信息,但是會影響性能。
注意:requestTraceFile這個系統屬性沒有zookeeper前綴,並且配置的變量名稱和系統屬性不一樣。
maxClientCnxns
沒有對應的Java系統屬性
在socket級別限制單個客戶端到ZooKeeper集群中單台服務器的並發連接數量,可以通過IP地址來區分不同的客戶端。它用來阻止某種類型的DoS攻擊,包括文件描述符資源耗盡。默認值是60。將值設置為0將完全移除並發連接的限制。
clientPortAddress
服務器監聽客戶端連接的地址(ipv4,ipv6或主機名),亦即客戶端嘗試連接到服務器上的地址。該參數是可選的,默認我們以這樣一種方式綁定,即對於服務器上任意 address/interface/nic,任何連接到clientPort的請求將會被接受。
minSessionTimeout
沒有對應的Java系統屬性
服務器允許客戶端會話的最小超時時間,以毫秒為單位。默認值是2倍的tickTime。
maxSessionTimeout
沒有對應的Java系統屬性
服務器允許客戶端會話的最大超時時間,以毫秒為單位。默認值是20倍的tickTime。
fsync.warningthresholdms
對應的Java系統屬性:fsync.warningthresholdms。
用於配置ZooKeeper進行事務日志(WAL)fsync操作消耗時間的報警閾值,一旦超過這個閾值將會打印輸出報警日志。該參數的默認值是1000,以毫秒為單位。參數值只能作為系統屬性來設置。
autopurge.snapRetainCount
沒有對應的Java系統屬性。
當啟用自動清理功能后,ZooKeeper將只保留autopurge.snapRetainCount個最近的數據快照(dataDir)和對應的事務日志文件(dataLogDir),其余的將會刪除掉。默認值是3。最小值也是3。
autopurge.purgeInterval
沒有對應的Java系統屬性。
用於配置觸發清理任務的時間間隔,以小時為單位。要啟用自動清理,可以將其值設置為一個正整數(大於 1)。默認值是0。
syncEnabled
對應的Java系統屬性:zookeeper.observer.syncEnabled。
和參與者一樣,觀察者現在默認將事務日志以及數據快照寫到磁盤上,這將減少觀察者在服務器重啟時的恢復時間。將其值設置為“false”可以禁用該特性。默認值是 “true”。
四、集群配置選項說明
本節中的選項主要用於ZooKeeper集群。
electionAlg
沒有對應的Java系統屬性。
用於選擇使用的Leader選舉算法。”0”對應於原始的基於UDP的版本,“1”對應於快速Leader選舉基於UDP的無身份驗證的版本,“2”對應於快速Leader選舉有基於UDP的身份驗證的版本,而“3”對應於快速Leader選舉基於TCP的版本。目前默認值是算法3。
注意:Leader選舉0,1,2這三種實現已經廢棄,在接下來的版本中將會移除它們,這樣就只剩下FastLeaderElection算法。
initLimit
沒有對應的Java系統屬性。
默認值是10,即tickTime屬性值的10倍。它用於配置允許Followers連接並同步到Leader的最大時間。如果ZooKeeper管理的數據量很大的話可以增加這個值。
leaderServes
對應的Java系統屬性:zookeeper.leaderServes。
用於配置Leader是否接受客戶端連接,默認值是“yes”,即Leader將會接受客戶端連接。在ZooKeeper中,Leader服務器主要協調事務更新請求。對於事務更新請求吞吐很高而讀取請求吞吐很低的情況可以配置Leader不接受客戶端連接,這樣就可以專注於協調工作。
注意:當ZooKeeper集群中服務器的數量超過3個時,建議開啟Leader選舉。
server.x=[hostname]:nnnnn:nnnnn
沒有對應的Java系統屬性。
組成ZooKeeper集群的服務器。當服務器啟動時,可以通過查找數據目錄中的myid文件來決定它是哪一台服務器。myid文件包含服務器編號,並且它要匹配“server.x”中的x。
客戶端用來組成ZooKeeper集群的服務器列表必須和每個ZooKeeper服務器中配置的ZooKeeper服務器列表相匹配。
有兩個端口號nnnnn,第一個是Followers用來連接到Leader,第二個是用於Leader選舉。如果想在單台機器上測試多個服務,則可以為每個服務配置不同的端口。
syncLimit
沒有對應的Java系統屬性。
默認值是5,即tickTime屬性值的5倍。它用於配置Leader和Followers間進行心跳檢測的最大延遲時間。如果在設置的時間內Followers無法與Leader進行通信,那么Followers將會被丟棄。
group.x=nnnnn[:nnnnn]
沒有對應的Java系統屬性。
Enables a hierarchical quorum construction.”x” 是一個組的標識,等號右邊的數字對應於服務器的標識。賦值操作右邊是冒號分隔的服務器標識。注意:組必須是不相交的,並且所有組聯合后必須是 ZooKeeper 集群。
weight.x=nnnnn
沒有對應的Java系統屬性。
和“group”一起使用,當形成集群時它給每個服務器賦權重值。這個值對應於投票時服務器的權重。ZooKeeper中只有少數部分需要投票,比如Leader選舉以及原子的廣播協議。服務器權重的默認值是1。如果配置文件中定義了組,但是沒有權重,那么所有服務器的權重將會賦值為1。
cnxTimeout
對應的Java系統屬性:zookeeper.cnxTimeout。
用於配置Leader選舉過程中,打開一次連接(選舉的Server互相通信建立連接)的超時時間。默認值是5s。
五、身份認證和授權選項說明
本節的選項允許通過身份認證和授權來控制服務執行。
zookeeper.DigestAuthenticationProvider.superDigest
對應的Java系統屬性:zookeeper.DigestAuthenticationProvider.superDigest。
該功能默認是禁用的。
能夠使ZooKeeper集群管理員可以作為一個“super”用戶來訪問ZNode層級結構。特別是對於一個已經認證為超級管理員的用戶不需要ACL檢查。
org.apache.zookeeper.server.auth.DigestAuthenticationProvider可以用來生成superDigest,調用它帶有“super:“參數的方法。當啟動集群中的每台服務器時,將生成的“super:“作為系統屬性提供。
當ZooKeeper客戶端向ZooKeeper服務器進行身份認證時,會傳遞一個“digest”和“super:“的認證數據。注意摘要式身份驗證將認證數據以普通文本的形式傳遞給服務器,在網絡中需要謹慎使用該認證方法,要么只在本機上或通過一個加密的連接。
六、實驗性選項/特性說明
本節列舉了一些目前還處於實驗階段的新特性。
服務器只讀模式
對應的Java系統屬性:readonlymode.enabled。
將其設置為true將會啟用服務器只讀模式支持,默認是禁用的。ROM允許請求了ROM支持的客戶端會話連接到服務器,即使當服務器可能已經從集群中分隔出去。在該模式中,ROM客戶端仍然可以從ZK服務中讀取值,但是不能進行寫操作以及看見其它客戶端所做的一些變更。更多詳細信息可以參見ZOOKEEPER-784獲取更多詳細信息。
不安全的選項
下面的選項會很有用,但是使用的時候需要特別小心。
forceSync
對應的Java系統屬性:zookeeper.forceSync。
用於配置是否需要在事務日志提交的時候調用FileChannel.force來保證數據完全同步到磁盤。默認值是“yes”。如果該選項設置為“no”,ZooKeeper將不會強制同步事務更新日志到磁盤。
jute.maxbuffer
對應的Java系統屬性:jute.maxbuffer。沒有zookeeper前綴。
用於指定一個ZNode中可以存儲數據量的最大值,默認值是0xfffff,或1M內。如果這個選項改變了,那么該系統屬性必須在所有的服務端和客戶端進行設置,否則會出現問題。ZooKeeper旨在存儲大小為千字節數量的數據。
skipACL
對應的Java系統屬性:zookeeper.skipACL。
用於配置ZooKeeper服務器跳過ACL權限檢查。這將一定程度的提高服務器吞吐量,但是也向所有客戶端完全開放數據訪問。
quorumListenOnAllIPs
當設置為true時,ZooKeeper服務器將會在所有可用的IP地址上監聽來自其對等點的連接請求,而不僅是配置文件的服務器列表中配置的地址。它會影響處理ZAB協議和Fast Leader Election協議的連接。默認值是false。
七、ZooKeeper優化建議
1、將ZooKeeper與其他應用分開部署,避免相互影響;
對於ZooKeeper來說,如果在運行過程中,需要和其它應用程序來競爭磁盤、CPU、網絡、內存資源,那么整體性能將會大打折扣。我們在使用ZooKeeper初期嘗試將ZooKeeper與其他應用公用機器,在系統流量上漲后,由於IO及CPU被其他應用使用很大,造成ZooKeeper的Session經常超時甚至應用與ZooKeeper的連接斷開。因此,建議ZooKeeper與其他應用分開部署;
2、將數據文件和事務日志分開存放,提高ZooKeeper性能;
我們先分析一下磁盤對ZooKeeper性能的影響。客戶端對ZK的更新操作都是永久的,不可回退的。為做到這點,ZK會將每次更新操作以事務日志的形式寫入磁盤,寫入成功后才會給予客戶端響應。明白這點之后,你就會明白磁盤的吞吐性能對於ZK的影響了,磁盤寫入速度制約着ZK每個更新操作的響應。因此,我們在選擇機型時盡量選擇多塊硬盤的機器,ZK的事務日志輸出是一個順序寫文件的過程,本身性能是很高的,所以盡量保證不要和其它隨機寫的應用程序共享一塊磁盤,盡量避免對磁盤的競爭。
3、盡量避免內存與磁盤空間的交換,確保設置一個合理的JVM堆大小;
如果設置太大,會讓內存與磁盤進行交換,這將使ZK的性能大打折扣。例如一個4G內存的機器的,如果你把JVM的堆大小設置為4G或更大,那么會使頻繁發生內存與磁盤空間的交換,通常設置成3G就可以了。
八、啟動內存設置實例
新建zookeeper/conf/java.env文件。
java.env文件內容如下:
#!/bin/sh export JAVA_HOME=/usr/java/jdk # heap size MUST be modified according to cluster environment export JVMFLAGS=”-Xms512m -Xmx1024m $JVMFLAGS”
對於內存的分配,還是根據項目和機器情況而定。如果內存夠用,適當的大點可以提升ZK性能。
ZooKeeper配置文件修改如下:
maxClientCnxns=1000 minSessionTimeout=30000 maxSessionTimeout=60000
九、日志優化實例
log4j配置,由於ZK是通過nohup啟動的,會有一個zookeeper.out日志文件,該文件中記錄的是輸出到console的日志。log4j中只要配置輸出到console即可,zookeeper.out日積月累會不斷變大,要放在容量大的磁盤上。
修改配置文件(zoo.cfg)如下:
zookeeper.root.logger=INFO, CONSOLE zookeeper.console.threshold=INFO log4j.rootLogger=${zookeeper.root.logger} log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold} log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
zoo.cfg文件中,dataDir是存放快照數據的,dataLogDir是存放寫前日志的。這兩個目錄不要配置成一個路徑,要配置到不同的磁盤上。如果磁盤是使用了RAID,系統就一塊磁盤,那配置到一塊磁盤上也可以。寫前日志的部分對寫請求的性能影響很大,保證dataLogDir所在磁盤性能良好。
十、其它優化配置實例
1、zoo.cfg文件中skipACL=yes,忽略ACL驗證,可以減少權限驗證的相關操作,提升一點性能。
2、zoo.cfg文件中forceSync=no,這個對寫請求的性能提升很有幫助,是指每次寫請求的數據都要從pagecache中固化到磁盤上,才算是寫成功返回。當寫請求數量到達一定程度的時候,后續寫請求會等待前面寫請求的forceSync操作,造成一定延時。如果追求低延時的寫請求,配置forceSync=no,數據寫到pagecache后就返回。但是機器斷電的時候,pagecache中的數據有可能丟失。
3、zk的dataDir和dataLogDir路徑下,如果沒有配置ZK自動清理,會不斷的新增數據文件。可配置成ZK系統自動清理數據文件,但是最求系統最高性能的話,建議人工手動清理文件:
zkCleanup.sh -n 3
這樣保留三份文件。
4、配置fsync.warningthresholdms=20,單位是毫秒,在forceSync=yes的時候,如果數據固化到磁盤的操作fsync超過20ms的時候,將會在zookeeper.out中輸出一條warn日志。這個目前zk的3.4.5和3.5版本有bug,在zoo.cfg中配置不生效。我的做法是在conf/java.env中添加java系統屬性:
export JVMFLAGS="-Dfsync.warningthresholdms=20 $JVMFLAGS"
參考:
http://www.chinacloud.cn/upload/2014-04/14042009468555.pdf
http://blog.csdn.net/u013673976/article/details/50153631
http://zlfwmm.blog.51cto.com/5892198/1710111
http://www.52yunwei.net/767.html(以上部分內容轉自此篇文章)
http://www.cnblogs.com/fanweiwei/p/4517012.html(以上內容部分轉自此篇博客)