天天看點

一次線上OOM故障排查經過

轉貼:http://my.oschina.net/flashsword/blog/205266

本文是一次線上OOM故障排查的經過,内容比較基礎但是真實,主要是記錄一下,沒有OOM排查經驗的同學也可以參考。

我們之前有一個計算作業。最近經常出現不穩定,無法正常響應的情況。具體表現是:各種連接配接逾時,從mysql、mongodb和zookeeper到netty,能逾時的都逾時過了。其他看不到太多有效的異常。

是以我們首先懷疑的是網絡問題,打電話跟運維确認,運維說網絡問題的可能性幾乎為0,因為我們的機器是虛機,主控端上的其他裝置都運轉正常。程式問題的可能性更大。繼續從應用日志和tomcat的catalina.out中查找日志,發現有一些OutOfMemoryError異常。實際上,出現這個異常就代表記憶體不夠了。

一次線上OOM故障排查經過

Memory Free已經接近了0,同時産生了大量的fullgc。

回到之前的連接配接timeout,我們知道,Java的連接配接timeout,除了網絡傳輸的時間,也包括了Java程式處理的時間,是以OOM導緻timeout也不奇怪了。

之前JVM分析做的很少,在同僚的幫助下,結合一點資料,完成了基本的分析。

首先可用的是

<code>1</code>

<code>jmap -histo PID</code>

這個指令會将記憶體中最終儲存的對象列出來。

一次線上OOM故障排查經過

其中”[“表示數組,例如”[B"是byte[],具體可以看<code>Class.getName()</code>的Javadoc。

但是這個隻能粗略定位原因,如果要仔細分析,需要知道是哪些個對象持有了它,這個時候,就需要dump記憶體下來,再離線分析了。

dump記憶體的指令是:

<code>jmap -dump:format=b,file=/home/admin/dump.bin PID</code>

此操作異常耗時,我跟運維在假死的機器上嘗試了幾次,竟然把tomcat程序幹掉了,使用時還是小心為妙…跟同僚讨論,認為<code>jmap -dump</code>實際上也是往運作的JVM執行個體發送一個dump請求,是以如果執行個體記憶體不足,dump很可能會失敗。比較好的做法是先降低一部分負載(比如把線上的機器先切下線)再試。

我這裡使用<code>VisualVM</code>進行分析,大緻效果如下:

一次線上OOM故障排查經過

這裡選擇“計算保留大小”。這個保留大小是遞歸計算執行個體之間的依賴,得到的總大小。因為去掉了循環依賴,是以并不完全準确,但是用于排查夠了。選擇保留大小最大的執行個體,一般就是罪魁禍首了!

一次線上OOM故障排查經過

最後排查出的結果,是公司的RPC中間件使用了ThreadLocal來儲存一個context,但是最後卻沒有釋放。按照架構組的說明,更新了版本,問題解決!