這段時間來,也在和公司裏的一些同窗交流使用zk的心得,整理了一些常見的zookeeper問題。這個頁面的目標是解答一些zk常見的使用問題,同時也讓你們明確zk不能幹什麼。頁面會一直更新。html
1. 客戶端對ServerList的輪詢機制是什麼
隨機,客戶端在初始化( new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) )的過程當中,將全部Server保存在一個List中,而後隨機打散,造成一個環。以後從0號位開始一個一個使用。
兩個注意點:1. Server地址可以重複配置,這樣可以彌補客戶端沒法設置Server權重的缺陷,可是也會加大風險。(好比: 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181). 2. 若是客戶端在進行Server切換過程當中耗時過長,那麼將會收到SESSION_EXPIRED. 這也是上面第1點中的加大風險之處。更多關於客戶端地址列表相關的,請查看文章《ZooKeeper客戶端地址列表的隨機原理》java
2.客戶端如何正確處理CONNECTIONLOSS(鏈接斷開) 和 SESSIONEXPIRED(Session 過時)兩類鏈接異常
在ZooKeeper中,服務器和客戶端之間維持的是一個長鏈接,在 SESSION_TIMEOUT 時間內,服務器會肯定客戶端是否正常鏈接(客戶端會定時向服務器發送heart_beat),服務器重置下次SESSION_TIMEOUT時間。所以,在正常狀況下,Session一直有效,而且zk集羣全部機器上都保存這個Session信息。在出現問題狀況下,客戶端與服務器之間鏈接斷了(客戶端所鏈接的那臺zk機器掛了,或是其它緣由的網絡閃斷),這個時候客戶端會主動在地址列表(初始化的時候傳入構造方法的那個參數connectString)中選擇新的地址進行鏈接。
好了,上面基本就是服務器與客戶端之間維持長鏈接的過程了。在這個過程當中,用戶可能會看到兩類異常CONNECTIONLOSS(鏈接斷開) 和SESSIONEXPIRED(Session 過時)。
CONNECTIONLOSS發生在上面紅色文字部分,應用在進行操做A時,發生了CONNECTIONLOSS,此時用戶不須要關心個人會話是否可用,應用所要作的就是等待客戶端幫咱們自動鏈接上新的zk機器,一旦成功鏈接上新的zk機器後,確認剛剛的操做A是否執行成功了。
SESSIONEXPIRED發生在上面藍色文字部分,這個一般是zk客戶端與服務器的鏈接斷了,試圖鏈接上新的zk機器,這個過程若是耗時過長,超過 SESSION_TIMEOUT 後尚未成功鏈接上服務器,那麼服務器認爲這個session已經結束了(服務器沒法確認是由於其它異常緣由仍是客戶端主動結束會話),開始清除和這個會話有關的信息,包括這個會話建立的臨時節點和註冊的Watcher。在這以後,客戶端從新鏈接上了服務器在,可是很不幸,服務器會告訴客戶端SESSIONEXPIRED。此時客戶端要作的事情就看應用的複雜狀況了,總之,要從新實例zookeeper對象,從新操做全部臨時數據(包括臨時節點和註冊Watcher)。git
3. 不一樣的客戶端對同一個節點是否能獲取相同的數據github
4. 一個客戶端修改了某個節點的數據,其它客戶端可以立刻獲取到這個最新數據嗎apache
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().api
5. ZK爲何不提供一個永久性的Watcher註冊機制服務器
不支持用持久Watcher的緣由很簡單,ZK沒法保證性能。
6. 使用watch須要注意的幾點網絡
a. Watches通知是一次性的,必須重複註冊.
b. 發生CONNECTIONLOSS以後,只要在session_timeout以內再次鏈接上(即不發生SESSIONEXPIRED),那麼這個鏈接註冊的watches依然在。
c. 節點數據的版本變化會觸發NodeDataChanged,注意,這裏特地說明了是版本變化。存在這樣的狀況,只要成功執行了setData()方法,不管內容是否和以前一致,都會觸發NodeDataChanged。
d. 對某個節點註冊了watch,可是節點被刪除了,那麼註冊在這個節點上的watches都會被移除。
e. 同一個zk客戶端對某一個節點註冊相同的watch,只會收到一次通知。即session
for( int i = 0; i < 3; i++ ){ zk.getData( path, true, null ); zk.getChildren( path, true ); }
f. Watcher對象只會保存在客戶端,不會傳遞到服務端。運維
7.我可否收到每次節點變化的通知
若是節點數據的更新頻率很高的話,不能。
緣由在於:當一次數據修改,通知客戶端,客戶端再次註冊watch,在這個過程當中,可能數據已經發生了許屢次數據修改,所以,千萬不要作這樣的測試:"數據被修改了n次,必定會收到n次通知"來測試server是否正常工做。(我曾經就作過這樣的傻事,發現Server一直工做不正常?其實不是)。即便你使用了GitHub上這個客戶端也同樣。
8.能爲臨時節點建立子節點嗎
不能。
9. 是否能夠拒絕單個IP對ZK的訪問,操做
ZK自己不提供這樣的功能,它僅僅提供了對單個IP的鏈接數的限制。你能夠經過修改iptables來實現對單個ip的限制,固然,你也能夠經過這樣的方式來解決。https://issues.apache.org/jira/browse/ZOOKEEPER-1320
10. 在getChildren(String path, boolean watch)是註冊了對節點子節點的變化,那麼子節點的子節點變化能通知嗎
不能
11.建立的臨時節點何時會被刪除,是鏈接一斷就刪除嗎?延時是多少?
鏈接斷了以後,ZK不會立刻移除臨時數據,只有當SESSIONEXPIRED以後,纔會把這個會話創建的臨時數據移除。所以,用戶須要謹慎設置Session_TimeOut
12. zookeeper是否支持動態進行機器擴容?若是目前不支持,那麼要如何擴容呢?
截止2012-03-15,3.4.3版本的zookeeper,還不支持這個功能,在3.5.0版本開始,支持動態加機器了,期待下吧: https://issues.apache.org/jira/browse/ZOOKEEPER-107
13. ZooKeeper集羣中個服務器之間是怎樣通訊的?
Leader服務器會和每個Follower/Observer服務器都創建TCP鏈接,同時爲每一個F/O都建立一個叫作LearnerHandler的實體。LearnerHandler主要負責Leader和F/O之間的網絡通信,包括數據同步,請求轉發和Proposal提議的投票等。Leader服務器保存了全部F/O的LearnerHandler。
14.zookeeper是否會自動進行日誌清理?若是進行日誌清理?
zk本身不會進行日誌清理,須要運維人員進行日誌清理,詳細關於zk的日誌清理,能夠查看《ZooKeeper日誌清理》