天天看點

zookeeper OOM問題排查背景分析總結

最近折騰的資料庫同步項目中,大量使用了zookeeper(版本3.3.3),可以說是強依賴,但是最近頻頻出現zookeeper記憶體使用率達到100%,而且是gc不掉,直接導緻整個系統挂起,傷不起阿

因為大部分的情況都是無法gc回收,是以很大程度上懷疑出現memory leak。

設定了jvm參數,收集了一下oom導緻jvm crash之後的日志檔案進行分析

zookeeper OOM問題排查背景分析總結

</h3>

zookeeper OOM問題排查背景分析總結

官方說明: http://zookeeper.apache.org/doc/trunk/zookeeperobservers.html 

主要用于解決讀擴充性的問題,observer的節點不參與vote,也就是說寫操作都隻會發生在leader/follower中進行投票決策,而observer就是一個隻讀鏡像。

但有一點和資料庫的master/slave模式不同的是,observer也會接受寫請求,但會将請求轉交給leader/follower叢集進行處理,并同步等待傳回結果。

可以說observer比較巧妙的解決了讀擴充性的問題,在zookeeper3.4.5版本,增加了readonlymode,和observer模式還是有所不同。

在我之前的文章中,zookeeper項目使用幾點小結,有描述在項目中使用observer的情況: 

zookeeper OOM問題排查背景分析總結

從圖中可以看出: 

1.  整個zookeeper大叢集有2部分組成,杭州的一個leader/follower叢集  +  美國的一個observer叢集

2.  為保證可用性,杭州叢集的機器分别部署在3個機房中,(滿足任意機房ab, 機房a+機房b  &gt;  機房a+機房b+機房c/2),最小的部署結構為3+2+2機器,這樣可以確定,任何一個機房挂了,都可以保證整個zookeeper叢集的可用性

有了以上的背景分析,再回到memory leak問題上來,翻了下zookeeper issue,發現還真有送出對應的memory leak問題,https://issues.apache.org/jira/browse/zookeeper-1303 

看完issue後,這時候問題已經明顯了。 

在leader.java類中:

這裡面leader節點,在與對應的follower/observer之間的連結異常斷開時,會清理目前記憶體中的引用句柄 (不然下次的vote資訊還會發送到挂了的節點上)。

而leader在往observer上推送write資料,會周遊目前記憶體中的observinglearners清單

再看一下learnerhandler.java類中:

learnerhandler中的處理方式是一種典型的異步處理,通過queuedpackets接受任務資料,然後線程異步進行消費處理。 因為observer可能因為網絡抖動,會斷開與leader之間的連結,就會觸發shutdown方法。而shutdown方法就是嘗試将自己從leader的observer句柄中移除

是以整個問題原因已經比較明确,removelearnerhandler沒有清理observer隊列中的句柄,導緻一直進行queuepacket調用,又沒有異步線程進行消費,是以暴記憶體是遲早的事。

特别注意:3.3.6中居然沒修複這個問題,是以可更新zookeeper至3.4.5, 經過實際驗證大家可放心更新(我的client 3.3.6 , server 3.4.5)

zookeeper 3.4和3.3的相容性描述: http://blog.cloudera.com/blog/2011/11/apache-zookeeper-3-4-0-has-been-released/