記一次jvm瘋狂gc導致CPU飆高的問題解決


記錄一次java虛擬機CPU飆高的異常處理

線上web服務器不時的出現非常卡的情況,登錄服務器top命令發現服務器CPU非常的高,

重啟tomcat之后CPU恢復正常,半天或者一天之后又會偶現同樣的問題。

解決問題首先要找到問題的爆發點,對於偶現的問題是非常難於定位的。

重啟服務器之后只能等待問題再次出現,這時候首先懷疑是否某個定時任務引發大量計算或者某個請求引發了死循環,

所以先把代碼里面所有懷疑的地方分析了一遍,加了一點日志,結果第二天下午問題再次出現,

這次的策略是首先保護案發現場,因為線上是兩個點,把一個點重啟恢復之后把另一個點只下線不重啟保留犯罪現場。

在問題的服務器上首先看業務日志,沒有發現大量重復日志,初步排除死循環的可能,接下來只能分析jvm了。

第一步:top命令查看占用CPU的pid

 

這是事后的截圖,當時的cpu飆高到500多,pid是27683

然后ps aux | grep 27683 搜索一下確認一下是不是我們的tomcat占用的cpu,這個基本是可以肯定的,因為tomcat重啟之后CPU立馬就降下來了。

也可以使用jps顯示java的pid

第二步:top -H -p 27683 查找27683下面的線程id,顯示線程的cpu的占用時間,占用比例,發現有很多個線程都會CPU占用很高,只能每個排查。

 

第三步:jstack查看線程信息,命令: jstack 27683 >> aaaa.txt 輸出到文本中再搜索,也可以直接管道搜索 jstack 27683 | grep "6c23" 這個線程id是16進制表示,需要轉一下,可以用這個命令轉 printf "%x\n" tid 也可以自己計算器轉一下。

悲劇的是我在排查的時候被引入了一個誤區,當時搜索到6c26這個線程的時候,發現是在做gc,瘋狂gc導致的線程過高,但是找不到哪里造成的產生這么多對象,一直在找所有可能的死循環和可能的內存泄露

 

然后通過命名 jstat -gcutil 【PID】 1000 100 查看每秒鍾gc的情況

 

這個是事后復盤的截圖,當時的截圖已經沒有了

發現S0不停的再新建對象,然后gc,不停的反復如此gc,去看堆棧信息,沒有什么發現,無非都是String和map對象最多,確定不了死循環的代碼,也找不到問題的爆發點,至此陷入徹底的困惑。一番查找之后確認也不是內存泄露,苦苦尋找無果,我陷入了沉思。

CPU還是一直保持在超高,無奈之下,還是jstack 27683 看線程棧,無目的的亂看,但是發現了一個問題,當前的點我是下線的也就是沒有用戶訪問的,CPU還是一直這么高,而且線程棧也在不停的打印,那么也就是說當前還在運行的線程很可能就是元凶,馬上分析線程棧信息,有了重大發現。

 

大量的這個線程信息出現,httpProxy_jsp這個jsp的線程在不停的活躍,這個是什么鬼jsp?難道服務器被攻擊了?馬上去代碼里找,發現確實有這個jsp,查看git的提交記錄,是幾天之前另一個同事提交的代碼,時間點和問題第一次出現的時間非常吻合,感覺自己運氣好應該是找到問題的點了,把同事叫過來分析他的代碼,這個jsp其實非常簡單,就是做一個代理請求,發起了一個后端http請求

 

HttpRequestUtil如下,是同事自己寫的工具類,沒有用公用工具,其中一個post方法里connection沒有設置鏈接超時時間和read超時時間:

 

這里面有個致命的問題,他http請求沒有設置超時等待時間,connection如果不設置超時時間或者0就認為是無窮大,也就是會一直都不超時,這時候如果被請求的第三方頁面如果不響應或者響應非常慢,這個請求就會一直的等待,或者是請求沒回來接着又來一次,導致這個線程就卡住了,但是線程堆積在這里又不崩潰還一直的在做某些事情會產生大量的對象,然后觸發了jvm不停的瘋狂GC把服務器CPU飈到了極限,然后服務器響應變得非常慢,問題終於找到了,而且非常符合問題的特點,果然把這個地方換了一種寫法加了2秒鍾超時的限制,問題沒有再出現。

這次問題的解決過程得出幾點心得:

1、jvm的問題是很復雜的,通過日志看到的很可能不是問題的根源,解決問題也有運氣成分,分析日志+業務場景+瞎蒙都是解決問題的方法,分析問題不要一條道走到黑,多結合當前的場景加上一些猜測。

2、這個問題的根源是CPU飆高,一開始總想着是代碼里有死循環,后來又以為是內存泄露,所以走了很多彎路,最后還是用最笨的方法看線程棧的日志看出了問題,所以問題沒有統一的解決方案,具體問題都要具體處理的,不能拘泥於以往的經驗。

3、在寫代碼過程中盡量使用原項目中已經被廣泛使用的公共工具類,盡量不要把自己自創的沒有經過項目檢驗的代碼引入工程,即使看起來很簡單的一段代碼可能給項目引入災難,除非你有充足的把握了解你代碼的底層,比如這個超時的設置問題。
————————————————
版權聲明:本文為CSDN博主「番茄超蛋」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/hotthought/article/details/82987428


免責聲明!

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



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