JVM使用SWAP引發的GC耗時

一、問題發現

    收到開發反饋線上應用某臺機器有GC耗時情況,登錄改機器,查看gc日誌,過濾GC耗時的時間點

 
  1. $ awk '/application threads/&&$11>1 || /GC remark|GC concurrent/&&$(NF-1)>1' /home/q/xx/xx-app/logs/gc.log.0.current
  2. 2020-09-22T15:14:50.522+0800: 414339.613: Total time for which application threads were stopped: 1.5485152 seconds, Stopping threads took: 1.4468679 seconds
  3. 2020-09-23T14:08:39.983+0800: 496769.074: [GC concurrent-root-region-scan-start]
  4. 2020-09-23T14:08:40.129+0800: 496769.220: [GC concurrent-mark-start]
  5. 2020-09-23T14:08:44.453+0800: 496773.543: [GC concurrent-mark-end, 4.3237479 secs]
  6. 2020-09-23T14:08:44.484+0800: 496773.574: [GC remark 2020-09-23T14:08:44.484+0800: 496773.574: [Finalize Marking, 0.0685901 secs] 2020-09-23T14:08:44.552+0800: 496773.643: [GC ref-proc, 0.6058526 secs] 2020-09-23T14:08:45.158+0800: 496774.249: [Unloading, 12.1510679 secs], 13.2001619 secs]
  7. 2020-09-23T14:08:57.684+0800: 496786.775: Total time for which application threads were stopped: 13.2082159 seconds, Stopping threads took: 0.0006442 seconds
  8. 2020-09-23T14:08:57.854+0800: 496786.945: [GC concurrent-cleanup-start]
  9. 2020-09-23T14:09:01.397+0800: 496790.488: Total time for which application threads were stopped: 1.1119271 seconds, Stopping threads took: 0.0002674 seconds
  10. 2020-09-23T20:56:14.571+0800: 521223.662: Total time for which application threads were stopped: 1.0247786 seconds, Stopping threads took: 0.9523914 seconds

    可以明顯看到在14:08:44GC耗時長達13s,並且在14:08:44.484還有觸發GC remark(該階段處於STW),這會暫停線程,而這個耗時這對於很多服務來說是難以接受的

 

二、問題排查

    獲取到了GC耗時的時間後,我們通過監控平臺獲取的各個監控項,開始排查這個點有異常的指標,最終分析發現,在14.08分,SWAP出現了釋放資源、內存資源增長的情況

    

   爲啥會這樣呢?JVM用到了SWAP,GC釋放了這部分內存到memory?爲了驗證JVM是否用到swap,我們通過檢查proc下的進程內存資源佔用

 
  1. $ awk '/Swap:/{S+=$(NF-1)}END{print S/1024}' /proc/$(ps -ef | grep [x]xs-app | awk '{print $2}')/smaps
  2. 358.364

看到確實有用到358Mb的SWAP

    爲了驗證GC耗時與swap操作有必然關係,我們抽樣了幾十臺機器,使用ansible過濾耗時的GC日誌,通過時間點確認到GC耗時的時間點與swap操作的時間點確實是一致的

   但是爲什麼會用到swap呢?通過內核參數,我們看到系統默認的swappiness=60(即內存使用量達到100-60=40%)就可能會開始使用swap,而當時的內存使用率,我們通過監控看是已經有60%的,滿足使用swap的條件

 
  1. $ cat /proc/sys/vm/swappiness
  2. 60

 

三、問題分析

    當內存使用率達到水位線(vm.swappiness)時,linux會把一部分暫時不使用的內存數據放到磁盤swap去,以便騰出更多可用內存空間。當需要使用位於swap區的數據時,必須先將其換回內存中,當JVM進行GC時,需要對相應堆分區的已用內存進行遍歷;假如GC的時候,有堆的一部分內容被交換到SWAP中,遍歷到這部分的時候就需要將其交換回內存,而Linux對SWAP的回收是滯後的(SWAP操作會佔用CPU與系統IO),在高併發/QPS服務中,這種滯後帶來的結果是致命的(stw)

 

四、問題處理

    設置vm.swappiness=0(重啓應用釋放swap後生效),JVM應用盡量不適用swap,另外不要強制swapoff -a去釋放關閉swap,強制關閉會立即遍歷swap釋放到內存中,可能會引發系統IO或者其他問題

 
  1. # 臨時生效
  2. $ sysctl vm.swappiness=0
  3. # 或者
  4. $ echo 0 > /proc/sys/vm/swappiness
  5.  
  6. # 永久生效
  7. $ echo "vm.swappiness=0" >> /etc/sysctl.conf

 

參考資料: 

Memory Sizing for WebSphere Applications on System z Linux

How To Check Swap Usage Size and Utilization in Linux

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