一次JVM內存泄漏的簡單記錄

回到首頁☞

由於外包無外網權限,信息安全決定法律問題,所以詳細內容不粘貼,只是記錄大體流程。

1、問題描述

EC2反饋主機創建失敗,定位發現前置機出了問題。
基本鏈路是:ELB+openresty+tomcat(4)
4個tomcat 分別部署在4個獨立的VM上,堆內存設置爲4G.

2、問題定位

2.1 top

查看cpu 300%~700%的來回跳動。

2.2、tail catalina.out

發現內存溢出

2.3、kill 進程重啓

一分鐘不到內存溢出

2.4、jmap -histo pid

查看內存使用情況
[C 位列第一把交椅,3.5G的內存佔有量。
也就是String爆了。
怎麼分析?
看了下業務相關的類就是kafka較多。

2.5、分析kafka使用情況

MQCLIENT+ZK 4個topic80監聽200分區*50線程池。
xxs配置的1024k,難道是kafka消費程序爆掉了。
嘗試方案:
kafka jar升級,去除threadpool,完全採用監聽實例消費,80個降低一半40個,重啓服務。
依然一分鐘後掛掉。

2.6 dump

在tomcat啓動參數中加入兩個參數 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data01/tomcat/oom.hprof

啓動tomcat 內存就會爆掉,獲取oom.hprof 二進制文件,ftp到本地。

2.7 JDK工具jvisualvm

jvisualvm:功能強大的控制檯
導入 oom.hprof 文件
直接點擊內存泄漏的線程,查看日誌。

setLog 接口爆掉了。

2.8 內存泄漏繼續分析

大量請求並沒經過tomcat,已經在nginx+redis直接分流了,setLog是返回任務狀態,其實請求量不大,只是可能會出現日誌內容較大,導致post請求的body非常大。
setLog直接爆掉,說明有些特殊任務日誌在2G以上。
setLog做了大小控制,>16M 不再寫Mongodb,但是請求進入了Tomcat,導致JVM掛掉。

再次查看catalina的日誌,發現有三臺私有云主機自動上報日誌後直接掛掉。

2.9 確診日誌是否超大

通過自動化快速平臺下發任務去查看日誌大小。

cd /tmp/.....
ll -th

三臺私有云主機中的未上報日誌任務的日誌分別有:
>2G
>3G
>4G

2.10 先清理日誌確保生產正常

cd /tmp/.....
>job.log

2.11 確認處理方案

1、最好的方案是升級agent
舊的agent是有缺陷的,在web後臺程序中做日誌攔截意義不大,因爲進入tomcat就會爆掉。
最好的方案是在agent的pyhon程序中直接做日誌過濾,大於某個值例如10M就不要上報了。
如果有人下發自動化任務

select * from table

一個10G的表內容作爲日誌返回,會讓真個平臺掛死,是非常大的漏洞。

但是修改agent雖然把邏輯寫入了最底層,os端但是全量升級雲主機風險非常大。

2、nginx限流
openresty除了做了很多代理,和分流,其實還可以限流限量。

2.12 用nginx配置做快速方案

client_max_body_size 10m;

別看這麼一個小小的參數,確實是系統安全的一個保障。
並且只設置在setLog這個請求上,不會影響其他請求。getJob 還是可以下發超過1G以上的軟件安裝任務。

3、小結

這種問題遇到不容易,確實是個經典案例。
但是修改agent纔是最根本的解決方案,讓agent更健壯,雖然有全量覆蓋的壓力和風險,真心想把平臺做強,必須迎難而上。
當然如果你是外包,還是以政治爲主,必須按照領導想法來。

回到首頁☞

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