記一次JVM生產OOM及後續調優

2020年03月18日,開年第一個生產事故發送在我的項目組o(╥﹏╥)o

事故發生

在下午2點40時,收到了第一個客戶投訴,緊接着收到了第二個、第三個。
並且不斷的有各業務系統表示自己的系統出現了操作無響應的現象,如此大範圍的影響,推測大概率是網關的功能出現了問題。

事故定位

立馬上日誌平臺搜索Nginx處的請求日誌,果然在Nginx上發現了大量的499響應碼日誌,緊接着拿着top 1請求量的499接口來搜索安全網關的日誌,發現了大量的:java.lang.OutOfMemoryError: GC overhead limit exceeded,由於怕過年期間生產不穩定,從年前開始,已經很長時間都沒有發佈了,所以排除了新增的代碼BUG。

解決

那麼就有可能是長時間運行慢慢堆積的對象導致的OOM,直接重啓安全網關,重啓後成功解決。

覆盤

java.lang.OutOfMemoryError: GC overhead limit exceeded根據官方的解釋是在多次gc後效果極差拋出的OOM。
懷疑可能存在內存泄漏,直接分析OOM後的dump文件。
在這裏插入圖片描述
從Dominator Tree圖中排出佔用內存最大的top n對象,挨個查看它的GC root:
在這裏插入圖片描述
再切換到Histogram,同樣排出佔用內存最大的top n對象,挨個查看GC root。

調優

分析後發現skywalking和spring產生了大量的Class對象,skywalking產生了大量的Endpoint對象,spring產生了大量的動態代理對象。並沒有自身代碼產生的內存泄漏對象。

  1. 適當的調大JVM堆大小
  2. 進一步調查Endpoint對象,是否可以控制過期時間。

事故的調查期間還發現了服務自啓動以來只有過2次full gc,都是在啓動初期由於Metaspace空間不足擴容導致的full gc,所以還需要調整Metaspace空間。

-XX:MetaspaceSize=128M

另外,我還調低了MaxTenuringThreshold,這個參數影響進入老年代的年齡閾值。
因爲網關的對象都是請求級別的生命週期,分析gc日誌可以知道young gc平均在30s執行一次,MaxTenuringThreshold的默認值是15,會導致部分長期存活對象需要將近8分鐘的時間才能進入老年代,本來年輕代的空間就不大,再被這些長期存活對象一佔用,會使得young gc更加頻繁。

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