線上服務器內存使用量已達到90%報警(內存泄漏)


2016-05-06中午11:56,收到“[sentry2]2016-05-06 11:56:09 xxxxxxhost xxx.xxx.xxx.xxx 內存使用已達到90.18%”報警。首先在腦海浮現的, 應該哪里出現內存泄漏了

 

一、確認問題

馬上到 Sentry 監控系統查看了該服務的“ 服務器監控”指標,發現其中2台機器的 內存使用量都超過了90%,另外2台盡然沒有監控數據(以前是有的)。

Sentry服務器監控

對於另外2台服務器沒有監控數據,只好先登上去查看確認一下嘍。通過“ free -m”確認,線上服務器總內存共 7872MB,使用了 7098MB,還有 773MB(= 406 + 151 + 216) 空閑着,使用率為 90.16%(= 7098 / 7872)。(參考: free(1) - Linux manual pageLinux Used內存到底哪里去了? | 褚霸-余鋒

線上服務器內存使用量

從問題表現來看,該業務的4台機器都出現“ 內存使用量都超過了90%”。

 

二、排查問題

1. 對比一下該業務“ 服務器內存占用百分比”的歷史狀況

1.1 3月26日業務剛上線時,服務器內存占用百分比是 45%。
【服務器內存占用百分比】3月26日,業務剛上線時是45%

 

1.2 4月14日之前,服務器內存占用百分比穩定在 48%
【服務器內存占用百分比】4月14日之前,穩定在48%
 

 1.3 4月15日,服務器內存占用百分比突然從 48% 升到 61%

 

1.4 4月17日,服務器內存占用百分比穩定在 67%

 

1.5 4月18日到5月2日期間,服務器內存占用百分比穩定在 68%

 

1.6 5月3日直到5月6日的報警期間,服務器內存占用百分比又從 68% 升到 90%

 

從“ 服務器內存占用百分比”歷史數據的異常時間點(4月17日、5月3日)來看,我們自己都沒有發布上線過代碼,說明不是我們引起的。

 

2. 查看 Sentry 監控系統的“ 進程監控”指標,運維同學發現 logagent 進程內存占用了 580MB。他們剛優化了 logagent 組件,1分鍾在線平滑升級后(線上業務服務不需要重啟),內存從 580MB 降到 54MB,還是很可觀的。這樣 服務器的空閑內存又多出了500+MB,為排查線上問題流出了更多的時間。(當時 做得不夠好的地方,應該 只保留一台作為現場排查問題,重啟其他機器,避免線上可能因為所有機器 OOM 而導致整個服務不可用)(當時我們都沒看到 sentry_agent 進程占用了近 1.3GB 驚訝

 

 

 3. 內存泄漏的可能性最大,先驗證之

向有經驗的同學請教,說內存使用量飆高,一般都是 內存泄漏引起的。因為我們線上服務使用 Java 語言開發,所以先從 JVM 垃圾收集器 GC 入手,可以比較直觀地看出 JVM 內存狀況。( jstat -gcutil `pgrep -u mapp java` 1s

 

上圖輸出的每個字段的含義見 jstat -gcutil 命令參考文檔。從上圖看, Eden 區Eden Space (heap))內存占用每秒增長 1.5%, Survivor 區Survivor Space (heap),S0、S1)內存占用在一次垃圾收集后增長 1.2%, Old 區Tenured Generation (heap))內存占用在一次垃圾收集后增長 0.57%, Perm 區Permanent Generation (non-heap))內存一直占用 59.97%。 Young GC 平均耗時為 96.7ms ( = 358.407 / 3705),Full GC 平均耗時為 74.4ms(= 7.587 / 102)。

從“ gc 監控”看,也沒收到 Full GC 報警。同時查看 gc.log, ParNew GC 大約每隔幾分鍾觸發一次, CMS GC 大約每隔5個小時觸發一次,沒有 Full GC。從 JVM 內存監控數據來看,說明 GC 都正常的。

 

3. 哪些進程用了那么多內存

從上面@褚霸在《 Linux Used內存到底哪里去了?》總結的: 內存的去向主要有3個:1. 進程消耗,2. slab消耗,3. pagetable消耗。

先看一下線上服務器的 JVM 配置( jps -lv):

 

2628 org. apache.catalina.startup.Bootstrap -Djava.util.logging.config.file=/home/mapp/spyder/.default/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms4g -Xmx4g -XX: PermSize=96m -XX: MaxPermSize=256m -Xmn2g -XX: SurvivorRatio=10 -XX:+ UseConcMarkSweepGC -XX:+ UseCMSCompactAtFullCollection -XX: CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX: CMSInitiatingOccupancyFraction=80 -XX:+ DisableExplicitGC -verbose:gc -Xloggc:/home/mapp/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseCompressedOops -Djava.awt.headless=true -XX:+ HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/mapp/logs/java.hprof -XX: MaxDirectMemorySize=1g -XX:+ UseCMSInitiatingOccupancyOnly -XX:+ ExplicitGCInvokesConcurrent -Dsun.rmi.dgc.server.gcInterval=2592000000 -Dsun.rmi.dgc.client.gcInterval=2592000000 -Dsun. net.client.defaultConnectTimeout=10000 -Dsun. net.client.defaultReadTimeout=30000 -Dproject.name=xxxxxx -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -D catalina.base=/home/mapp/spyder/.default -D catalina.home=/

從 JVM 配置來看,最大內存為 4GB。

 

接着就是通過“ top -M”(按 RES字段排序:按 f,然后再按 q)觀察哪些進程占用的內存不正常。

 

top 命令的 VIRT 字段表示虛擬內存,而 RES 字段才表示實際的使用內存。從上圖(數據是事后偽造的,因為沒保存當時現場,但量級和當時事故現場差不多)可以很清晰地看到,java 進程占用了 4.1g 內存,和 JVM 配置一樣;兩個 sentry-agent 進程盡然分別占用了 1.6GB 和 1.2GB(好嚇人)。

 sentry-agent 是一個收集日志的客戶端,為什么會占用這么多的內存呢?向負責該服務的開發同學反饋,證實確實有問題,他們好像也發現問題了,他們答應當天下午修復問題。憑直覺,問題應該就出現在這里了。先讓運維同學 重啟了 sentry-agent 進程,內存占用百分比一下子就降到了 59%,說明 此問題的大部分原因是這里引起的。此數據 與4月15日吻合,但與最開始的48%數據還有差距,這個還需要進一步排查。因為從 GC 來看,自身應用程序沒發現內存泄漏問題,需要深入探究一下。

 上述4台機器,前面2台使用 Docker 虛擬化,后面2台使用 KVM 虛擬化。內存占用百分比相差10+個點(相差 900+MB),注意是由於 slabs 消耗不一樣引起的(參考@褚霸的文章)。

KVM 虛擬化:

$ echo `cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'` MB
139.037 MB

Docker 虛擬化:

$ echo `cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'` MB
1177.34 MB

 

問題解決前后,“內存占用百分比”對比圖:
【服務器內存占用百分比】問題定位到后,從84%下降到59%


 看了其他監控指標,發現“ 服務器線程總數”從680下降到400,說明 sentry-agent 存在線程泄漏問題
確定問題后,重啟sentry-agent進程,服務器線程總數從680下降到400
 

至此,本問題算是解決了大部分,線上服務器內存暴漲問題得到了解決。(在群里反饋,其他服務先前就已經出現了此問題,但一直沒有去排查,我也是醉啦,就不擔心出現 OOM 嗎?就不擔心整個服務都不可用嗎?這個問題解決得到 Leader 的贊還是很開心滴)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM