hadoop-Zookeeper常見問題整

背景

最近測試環境發現因爲zookeeper掛掉而導致hadoop集羣服務都掛掉的情況,zookeeper是集羣中不可或缺的組件,大部分的組件都依賴zookeeper,在此將zookeeper的一些概念性的東西整理出來,後面也會提及如何恢復zookeeper數據。

ZK選舉過程

當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的Server都恢復到一個正確的狀態。Zk的選舉算法使用ZAB協議:
選舉線程由當前Server發起選舉的線程擔任,其主要功能是對投票結果進行統計,並選出推薦的Server;
選舉線程首先向所有Server發起一次詢問(包括自己);
選舉線程收到回覆後,驗證是否是自己發起的詢問(驗證zxid是否一致),然後獲取對方的id(myid),並存儲到當前詢問對象列表中,最後獲取對方提議的leader相關信息(id,zxid),並將這些信息存儲到當次選舉的投票記錄表中;
收到所有Server回覆以後,就計算出zxid最大的那個Server,並將這個Server相關信息設置成下一次要投票的Server;
線程將當前zxid最大的Server設置爲當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數, 設置當前推薦的leader爲獲勝的Server,將根據獲勝的Server相關信息設置自己的狀態,否則,繼續這個過程,直到leader被選舉出來。
通過流程分析我們可以得出:要使Leader獲得多數Server的支持,則Server總數最好是奇數2n+1,且存活的Server的數目不得少於n+1

master/slave之間通信

Storm:定期掃描
PtBalancer:節點監聽

節點變多時,PtBalancer速度變慢

類似問題:根據Netflix的Curator作者所說,ZooKeeper真心不適合做Queue,或者說ZK沒有實現一個好的Queue,詳細內容可以看 https://cwiki.apache.org/confluence/display/CURATOR/TN4,
原因有五:
ZK有1MB 的傳輸限制。 實踐中ZNode必須相對較小,而隊列包含成千上萬的消息,非常的大。
如果有很多節點,ZK啓動時相當的慢。 而使用queue會導致好多ZNode. 你需要顯著增大 initLimit 和 syncLimit.
ZNode很大的時候很難清理。Netflix不得不創建了一個專門的程序做這事。
當很大量的包含成千上萬的子節點的ZNode時, ZK的性能變得不好
ZK的數據庫完全放在內存中。 大量的Queue意味着會佔用很多的內存空間。
儘管如此, Curator還是創建了各種Queue的實現。 如果Queue的數據量不太多,數據量不太大的情況下,酌情考慮,還是可以使用的。

客戶端對ServerList的輪詢機制是什麼

隨機,客戶端在初始化( new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) )的過程中,將所有Server保存在一個List中,然後隨機打散,形成一個環。之後從0號位開始一個一個使用。
兩個注意點:
Server地址能夠重複配置,這樣能夠彌補客戶端無法設置Server權重的缺陷,但是也會加大風險。(比如: 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181).
如果客戶端在進行Server切換過程中耗時過長,那麼將會收到SESSION_EXPIRED. 這也是上面第1點中的加大風險之處。更多關於客戶端地址列表相關的。

客戶端如何正確處理CONNECTIONLOSS(連接斷開) 和 SESSIONEXPIRED(Session 過期)兩類連接異常

在ZooKeeper中,服務器和客戶端之間維持的是一個長連接,在 SESSION_TIMEOUT 時間內,服務器會確定客戶端是否正常連接(客戶端會定時向服務器發送heart_beat),服務器重置下次SESSION_TIMEOUT時間。因此,在正常情況下,Session一直有效,並且zk集羣所有機器上都保存這個Session信息。在出現問題情況下,客戶端與服務器之間連接斷了(客戶端所連接的那臺zk機器掛了,或是其它原因的網絡閃斷),這個時候客戶端會主動在地址列表(初始化的時候傳入構造方法的那個參數connectString)中選擇新的地址進行連接。
好了,上面基本就是服務器與客戶端之間維持長連接的過程了。在這個過程中,用戶可能會看到兩類異常CONNECTIONLOSS(連接斷開) 和SESSIONEXPIRED(Session 過期)。
CONNECTIONLOSS發生在上面紅色文字部分,應用在進行操作A時,發生了CONNECTIONLOSS,此時用戶不需要關心我的會話是否可用,應用所要做的就是等待客戶端幫我們自動連接上新的zk機器,一旦成功連接上新的zk機器後,確認剛剛的操作A是否執行成功了。

一個客戶端修改了某個節點的數據,其它客戶端能夠馬上獲取到這個最新數據嗎

ZooKeeper不能確保任何客戶端能夠獲取(即Read Request)到一樣的數據,除非客戶端自己要求:方法是客戶端在獲取數據之前調用org.apache.zookeeper.AsyncCallback.VoidCallback, java.lang.Object) sync.
通常情況下(這裏所說的通常情況滿足:1. 對獲取的數據是否是最新版本不敏感,2. 一個客戶端修改了數據,其它客戶端需要不需要立即能夠獲取最新),可以不關心這點。
在其它情況下,最清晰的場景是這樣:ZK客戶端A對 /my_test 的內容從 v1->v2, 但是ZK客戶端B對 /my_test 的內容獲取,依然得到的是 v1. 請注意,這個是實際存在的現象,當然延時很短。解決的方法是客戶端B先調用 sync(), 再調用 getData().

ZK爲什麼不提供一個永久性的Watcher註冊機制

不支持用持久Watcher的原因很簡單,ZK無法保證性能。
使用watch需要注意的幾點
Watches通知是一次性的,必須重複註冊.
發生CONNECTIONLOSS之後,只要在session_timeout之內再次連接上(即不發生SESSIONEXPIRED),那麼這個連接註冊的watches依然在。
節點數據的版本變化會觸發NodeDataChanged,注意,這裏特意說明了是版本變化。存在這樣的情況,只要成功執行了setData()方法,無論內容是否和之前一致,都會觸發NodeDataChanged。
對某個節點註冊了watch,但是節點被刪除了,那麼註冊在這個節點上的watches都會被移除。
同一個zk客戶端對某一個節點註冊相同的watch,只會收到一次通知。即
Watcher對象只會保存在客戶端,不會傳遞到服務端。

我能否收到每次節點變化的通知

如果節點數據的更新頻率很高的話,不能。
原因在於:當一次數據修改,通知客戶端,客戶端再次註冊watch,在這個過程中,可能數據已經發生了許多次數據修改,因此,千萬不要做這樣的測試:”數據被修改了n次,一定會收到n次通知”來測試server是否正常工作。(我曾經就做過這樣的傻事,發現Server一直工作不正常?其實不是)。即使你使用了GitHub上這個客戶端也一樣。

能爲臨時節點創建子節點嗎

不能。

是否可以拒絕單個IP對ZK的訪問,操作

ZK本身不提供這樣的功能,它僅僅提供了對單個IP的連接數的限制。你可以通過修改iptables來實現對單個ip的限制,當然,你也可以通過這樣的方式來解決。 https://issues.apache.org/jira/browse/ZOOKEEPER-1320

在getChildren(String path, boolean watch)是註冊了對節點子節點的變化,那麼子節點的子節點變化能通知嗎

不能

創建的臨時節點什麼時候會被刪除,是連接一斷就刪除嗎?延時是多少?

連接斷了之後,ZK不會馬上移除臨時數據,只有當SESSIONEXPIRED之後,纔會把這個會話建立的臨時數據移除。因此,用戶需要謹慎設置Session_TimeOut

zookeeper是否支持動態進行機器擴容?如果目前不支持,那麼要如何擴容呢?

截止3.4.3版本的zookeeper,還不支持這個功能,在3.5.0版本開始,支持動態加機器了,期待下吧: https://issues.apache.org/jira/browse/ZOOKEEPER-107

ZooKeeper集羣中個服務器之間是怎樣通信的?

Leader服務器會和每一個Follower/Observer服務器都建立TCP連接,同時爲每個F/O都創建一個叫做LearnerHandler的實體。LearnerHandler主要負責Leader和F/O之間的網絡通訊,包括數據同步,請求轉發和Proposal提議的投票等。Leader服務器保存了所有F/O的LearnerHandler。

zookeeper是否會自動進行日誌清理?如何進行日誌清理?

zk自己不會進行日誌清理,需要運維人員進行日誌清理

數據文件管理

默認情況下,ZK的數據文件和事務日誌是保存在同一個目錄中,建議是將事務日誌存儲到單獨的磁盤上。
1 數據目錄
ZK的數據目錄包含兩類文件:
A、myid – 這個文件只包含一個數字,和serverid對應。
B、snapshot. - 按zxid先後順序的生成的數據快照。
集羣中的每臺ZK server都會有一個用於惟一標識自己的id,有兩個地方會使用到這個id:myid文件和zoo.cfg文件中。myid文件存儲在dataDir目錄中,指定了當前server的server id。在zoo.cfg文件中,根據server id,配置了每個server的ip和相應端口。Zookeeper啓動的時候,讀取myid文件中的server id,然後去zoo.cfg 中查找對應的配置。
zookeeper在進行數據快照過程中,會生成snapshot文件,存儲在dataDir目錄中。文件後綴是zxid,也就是事務id。(這個zxid代表了zk觸發快照那個瞬間,提交的最後一個事務id)。注意,一個快照文件中的數據內容和提交第zxid個事務時內存中數據近似相同。僅管如此,由於更新操作的冪等性,ZK還是能夠從快照文件中恢復數據。數據恢復過程中,將事務日誌和快照文件中的數據對應起來,就能夠恢復最後一次更新後的數據了。
2 事務日誌目錄
dataLogDir目錄是ZK的事務日誌目錄,包含了所有ZK的事務日誌。正常運行過程中,針對所有更新操作,在返回客戶端“更新成功”的響應前,ZK會確保已經將本次更新操作的事務日誌寫到磁盤上,只有這樣,整個更新操作纔會生效。每觸發一次數據快照,就會生成一個新的事務日誌。事務日誌的文件名是log.,zxid是寫入這個文件的第一個事務id。
3 文件管理
不同的zookeeper server生成的snapshot文件和事務日誌文件的格式都是一致的(無論是什麼環境,或是什麼樣的zoo.cfg 配置)。因此,如果某一天生產環境中出現一些古怪的問題,你就可以把這些文件下載到開發環境的zookeeper中加載起來,便於調試發現問題,而不會影響生產運行。另外,使用這些較舊的snapshot和事務日誌,我們還能夠方便的讓ZK回滾到一個歷史狀態。
另外,ZK提供的工具類LogFormatter能夠幫助可視化ZK的事務日誌,幫助我們排查問題,關於事務日誌的可以化,請查看這個文章《可視化zookeeper的事務日誌》.
需要注意的一點是,zookeeper在運行過程中,不斷地生成snapshot文件和事務日誌,但是不會自動清理它們,需要管理員來處理。(ZK本身只需要使用最新的snapshot和事務日誌即可)關於如何清理文件,上面章節“日常運維”有提到。

通過數據文件和事物日誌文件恢復zookeeper

選擇數據文件和事物文件,並複製到新的zookeeper服務數據目錄下(datadir):
Alt text

啓動新的zookeeper服務:
Alt text

查看zookeeper數據:
Alt text

從圖中可以看出數據已經恢復。

注意
如果集羣中有一臺zookeeper服務能正常啓動那就直接將其它的zookeeper服務重置即可(記得要備份數據目錄哦)。

日誌清理

在使用zookeeper過程中,我們知道,會有dataDir和dataLogDir兩個目錄,分別用於snapshot和事務日誌的輸出(默認情況下只有dataDir目錄,snapshot和事務日誌都保存在這個目錄中)。

ZK在完成若干次事務日誌之後(在ZK中,凡是對數據有更新的操作,比如創建節點,刪除節點或是對節點數據內容進行更新等,都會記錄事務日誌),ZK會觸發一次快照(snapshot),將當前server上所有節點的狀態以快照文件的形式dump到磁盤上去,即snapshot文件。這裏的若干次事務日誌是可以配置的,默認是100000,具體參看下文中關於配置參數“snapCount”的介紹。

考慮到ZK運行環境的差異性,以及對於這些歷史文件,不同的管理員可能有自己的用途(例如作爲數據備份),因此默認ZK是不會自動清理快照和事務日誌,需要交給管理員自己來處理。

這裏介紹4種清理日誌的方法。在這4種方法中,推薦使用第一種方法,對於運維人員來說,將日誌清理工作獨立出來,便於統一管理也更可控。畢竟zk自帶的一些工具並不怎麼給力,這裏是社區反映的兩個問題:
https://issues.apache.org/jira/browse/ZOOKEEPER-957
http://zookeeper-user.578899.n2.nabble.com/PurgeTxnLog-td6304244.html

第一種,也是運維人員最常用的,寫一個刪除日誌腳本,每天定時執行即可:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
         
#snapshot file dir
dataDir=/home/nileader/taokeeper/zk_data/version-2
#tran log dir
dataLogDir=/home/nileader/taokeeper/zk_log/version-2
#zk log dir
logDir=/home/nileader/taokeeper/logs
#Leave 60 files
count=60
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

以上這個腳本定義了刪除對應兩個目錄中的文件,保留最新的60個文件,可以將他寫到crontab中,設置爲每天凌晨2點執行一次就可以了。

第二種,使用ZK的工具類PurgeTxnLog,它的實現了一種簡單的歷史文件清理策略,可以在這裏看一下他的使用方法:http://zookeeper.apache.org/doc/r3.4.3/api/index.html,可以指定要清理的目錄和需要保留的文件數目,簡單使用如下:


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

第三種,對於上面這個Java類的執行,ZK自己已經寫好了腳本,在bin/zkCleanup.sh中,所以直接使用這個腳本也是可以執行清理工作的。
第四種,從3.4.0開始,zookeeper提供了自動清理snapshot和事務日誌的功能,通過配置 autopurge.snapRetainCount 和 autopurge.purgeInterval 這兩個參數能夠實現定時清理了。這兩個參數都是在zoo.cfg中配置的:
autopurge.purgeInterval 這個參數指定了清理頻率,單位是小時,需要填寫一個1或更大的整數,默認是0,表示不開啓自己清理功能。
autopurge.snapRetainCount 這個參數和上面的參數搭配使用,這個參數指定了需要保留的文件數目。默認是保留3個。


zkui配置過連接信息後,再切換到到其他,報如下錯誤:

KeeperErrorCode = ConnectionLoss for /


修改 ./config.cfg

   zkSessionTimeout=60

   zkServer


./target/config.cfg  

   zkSessionTimeout=60

   zkServer


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章