20180829系統超時問題回顧

背景:

       8月29日,凌晨4點左右,某服務告警,其中一個節點直接down掉,收到告警的同事讓運維重啓。

       9點左右,內存監控上發現內存異常,堆內存漲速很快,即便GC也沒有什麼效果,頻繁GC。

       9點38,服務各種超時,影響整個app使用。

處理方式:

       當時由於很想要堆棧數據,所以沒有讓運維立即新起服務,切換ip,而是先dump後再重啓服務,因爲這個,對其他服務造成了更大的影響。

場景模擬:

由於已沒有當時dump文件,這裏用的模擬的dump文件,需要的同學可根據後面鏈接中的代碼生成,

使用Memory Analyzer分析dump文件,使用介紹:https://blog.csdn.net/Jin_Kwok/article/details/80326088 ,https://www.jianshu.com/p/759e02c1feee

 

從上圖1,圖2來看,初步懷疑是ThreadGroupContext有問題,有太多的元素,而這個增長只通過java.beans.ThreadGroupContext#putBeanInfo方法觸發。

網上搜索ThreadGroupContext,介紹很少,再往上找是Introspector,懷疑是:Introspector持有BeanInfo的引用,無法回收,導致內存泄漏。見:https://www.jianshu.com/p/b167716f9c0c 

但這裏有個疑問是ThreadGroupContext中的是weakHashMap,當GC的時候應該是會被回收的。

從第三張圖(按Retained Heap倒序)來看,就明顯感覺有問題了,加載了過多的類,沒有得到釋放,從classLoader來看,應該是groovy動態加載類導致的,網上搜索groovy 內存泄漏,一大片。。見:

https://blog.csdn.net/jinzhencs/article/details/74562973,由於動態加載類無法釋放,將會擠用老年代內存,導致老年代可用內存持續減少,雖然一直GC但是效果甚微。

 

(盜圖,java8沒有Perm區,而是MetaSpace區)

總結:

       1. 以上是針對不容易復現線上問題的情況,如果方便復現,可以通過jconsole觀察,很直觀。

       2. 或許線上應該指定-XX:MaxMetaspaceSize,提前報OOM: Metaspace,快速失敗,把對外服務的影響降小。

       3. 如果再遇到類似問題,正確的處理方式,應該是立馬讓運維新起節點,隨時準備切換。在提前知道,且自己無法處理的情況下,告知上級或者同事一起解決。

模擬代碼:

maven配置
<dependency>
 <groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy-all</artifactId>
 <version>2.4.7</version>
</dependency>
   
模擬代碼:
public static void main(String[] args) {
      for (int i = 0; i < 1000000; i++) {
            new GroovyShell().evaluate("\"${0..9}-${0..9}\"");
      }
}
   
jvm參數:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=OOM.hprof
-Dfile.encoding=UTF-8
-Xms200M
-Xmx200M
-Xmn40M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:MetaspaceSize=30m
   
   
這裏沒有設置-XX:MaxMetaspaceSize ,如果設置了,會提前報java.lang.OutOfMemoryError: Metaspace
等執行到5分鐘左右就可以自己手動dump了,jmap -dump:format=b,file=fileName pid

 

參考:

          https://juejin.im/post/5b85ea54e51d4538dd08f601  (≈ 深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》)

 

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