1. 程式人生 > >叢集間同步導致的記憶體溢位

叢集間同步導致的記憶體溢位

有一個基於B/S的MIS系統,硬體為兩臺2個CPU,8GB記憶體的HP小型機,伺服器是WebLogic9.2,每臺機器啟動了3個WebLogic例項,構成一個6個節點的親合力式叢集。由於是親合式叢集,節點之間沒有進行Session同步,但是有一些需求要實現部分資料在各個節點間共享。開始這些資料存放在資料庫中,但由於讀寫頻繁競爭很激烈,效能影響較大,後面使用JBossCache構建了一個全域性快取。全域性快取啟用後,服務正常是用了一段較長的時間,但不定期的出現了多次的記憶體溢位問題。
在記憶體溢位異常不出現的時候,服務記憶體回收狀況一直正常,每次記憶體回收後都能恢復到一個穩定的 可用空間,開始懷疑是程式某些不常用的程式碼路徑中存在記憶體洩漏,但管理員反應最近程式並未更新,升級過,也沒有進行什麼特別操作。只好讓服務帶著 -XX:+HeapDumpOnOutOfMemoryError參與運行了一段時間。在最近一次溢位之後,管理員發回了heapdump檔案,發現裡面存在著大量的org.jgroups.pbcast.NAKACK物件。
JBossCache是基於自家的JGroups進行叢集間的資料通訊,JGroups使用協議棧的方式來實現收發資料包的各種所需特性自由組合,資料包接受和傳送時要經過每層協議棧的up()和down()方法,其中的NAKACK棧用於保障各個包的有效順序及重發。JBossCache協議棧如圖5-1所示:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20181031204524408.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjk1NzQ3OQ==,size_16,color_FFFFFF,t_70)	由於資訊在傳輸失敗需要重發的可能性,在確認所有註冊GMS (Group Membership Service) 的節點都收到正確的資訊前,傳送的資訊必須在記憶體中保留。而此MIS的服務端中有一個負責安全校驗的全域性Filter,每當接受的請求時,均會更新一次最後操作時間,並且將這個時間同步到所有的節點去,使得一個使用者在一段時間內不能在多臺機器上登入。在伺服器使用過程中,往往一個頁面會產生數次乃至數十次的請求,因此這個過濾器導致叢集各個節點之間網路互動非常頻繁。當網路情況不能滿足傳輸要求時,重發資料在記憶體中不斷堆積,很快產生了記憶體溢位。
這個案例中的問題,即有JBossCache的缺陷,也有MIS系統實現方式上缺陷。JBossCache官方的mailhst中討論過很多次類似的記憶體溢位異常問題,據說後續版本也有了改進。而更重要的缺陷是一類被叢集共享的資料要使用類似JBossCache這種叢集快取來同步的話,可以允許讀操作頻繁,因為資料在本地記憶體也有一份副本,讀取的動作不會消耗多少資源,但不應有過於頻繁的寫操作,那樣會帶來很大的網路同步的開銷。