jvm 崩溃日志设置_记一次JVM疯狂GC导致CPU飙高的问题解决
背景
線上web服務(wù)器不時(shí)的出現(xiàn)非??ǖ那闆r,登錄服務(wù)器top命令發(fā)現(xiàn)服務(wù)器CPU非常的高,重啟tomcat之后CPU恢復(fù)正常,半天或者一天之后又會出現(xiàn)同樣的問題。解決問題首先要找到問題的爆發(fā)點(diǎn),對于偶現(xiàn)的問題是非常難于定位的。
重啟服務(wù)器之后只能等待問題再次出現(xiàn),這時(shí)候首先懷疑是否某個(gè)定時(shí)任務(wù)引發(fā)大量計(jì)算或者某個(gè)請求引發(fā)了死循環(huán),所以先把代碼里面所有懷疑的地方分析了一遍,加了一點(diǎn)日志,結(jié)果第二天下午問題再次出現(xiàn),
這次的策略是首先保護(hù)案發(fā)現(xiàn)場,因?yàn)榫€上是兩個(gè)點(diǎn),把一個(gè)點(diǎn)重啟恢復(fù)之后把另一個(gè)點(diǎn)只下線不重啟保留犯罪現(xiàn)場。
排查
在問題的服務(wù)器上首先看業(yè)務(wù)日志,沒有發(fā)現(xiàn)大量重復(fù)日志,初步排除死循環(huán)的可能,接下來只能分析jvm了。
第一步:top命令查看占用CPU的pid
這是事后的截圖,當(dāng)時(shí)的cpu飆高到500多,pid是27683
然后ps aux | grep 27683 搜索一下確認(rèn)一下是不是我們的tomcat占用的cpu,這個(gè)基本是可以肯定的,因?yàn)閠omcat重啟之后CPU立馬就降下來了。
也可以使用jps顯示java的pid
第二步:top -H -p 27683 查找27683下面的線程id,顯示線程的cpu的占用時(shí)間,占用比例,發(fā)現(xiàn)有很多個(gè)線程都會CPU占用很高,只能每個(gè)排查。
第三步:jstack查看線程信息,命令:jstack 27683 >> aaaa.txt 輸出到文本中再搜索,也可以直接管道搜索 jstack 27683 | grep "6c23" 這個(gè)線程id是16進(jìn)制表示,需要轉(zhuǎn)一下,可以用這個(gè)命令轉(zhuǎn) printf "%x" tid 也可以自己計(jì)算器轉(zhuǎn)一下。
悲劇的是我在排查的時(shí)候被引入了一個(gè)誤區(qū),當(dāng)時(shí)搜索到6c26這個(gè)線程的時(shí)候,發(fā)現(xiàn)是在做gc,瘋狂gc導(dǎo)致的線程過高,但是找不到哪里造成的產(chǎn)生這么多對象,一直在找所有可能的死循環(huán)和可能的內(nèi)存泄露。
然后通過命名 jstat -gcutil 【PID】 1000 100 查看每秒鐘gc的情況。
這個(gè)是事后復(fù)盤的截圖,當(dāng)時(shí)的截圖已經(jīng)沒有了
發(fā)現(xiàn)S0不停的再新建對象,然后gc,不停的反復(fù)如此gc,去看堆棧信息,沒有什么發(fā)現(xiàn),無非都是String和map對象最多,確定不了死循環(huán)的代碼,也找不到問題的爆發(fā)點(diǎn),至此陷入徹底的困惑。一番查找之后確認(rèn)也不是內(nèi)存泄露,苦苦尋找無果,我陷入了沉思。
CPU還是一直保持在超高,無奈之下,還是jstack 27683 看線程棧,無目的的亂看,但是發(fā)現(xiàn)了一個(gè)問題,當(dāng)前的點(diǎn)我是下線的也就是沒有用戶訪問的,CPU還是一直這么高,而且線程棧也在不停的打印,那么也就是說當(dāng)前還在運(yùn)行的線程很可能就是元兇,馬上分析線程棧信息,有了重大發(fā)現(xiàn)。
大量的這個(gè)線程信息出現(xiàn),httpProxy_jsp這個(gè)jsp的線程在不停的活躍,這個(gè)是什么鬼jsp?難道服務(wù)器被攻擊了?馬上去代碼里找,發(fā)現(xiàn)確實(shí)有這個(gè)jsp,查看git的提交記錄,是幾天之前另一個(gè)同事提交的代碼,時(shí)間點(diǎn)和問題第一次出現(xiàn)的時(shí)間非常吻合,感覺自己運(yùn)氣好應(yīng)該是找到問題的點(diǎn)了,把同事叫過來分析他的代碼,這個(gè)jsp其實(shí)非常簡單,就是做一個(gè)代理請求,發(fā)起了一個(gè)后端http請求。
HttpRequestUtil如下,是同事自己寫的工具類,沒有用公用工具,其中一個(gè)post方法里connection沒有設(shè)置鏈接超時(shí)時(shí)間和read超時(shí)時(shí)間:
這里面有個(gè)致命的問題,他http請求沒有設(shè)置超時(shí)等待時(shí)間,connection如果不設(shè)置超時(shí)時(shí)間或者0就認(rèn)為是無窮大,也就是會一直都不超時(shí),這時(shí)候如果被請求的第三方頁面如果不響應(yīng)或者響應(yīng)非常慢,這個(gè)請求就會一直的等待,或者是請求沒回來接著又來一次,導(dǎo)致這個(gè)線程就卡住了,但是線程堆積在這里又不崩潰還一直的在做某些事情會產(chǎn)生大量的對象,然后觸發(fā)了jvm不停的瘋狂GC把服務(wù)器CPU飚到了極限,然后服務(wù)器響應(yīng)變得非常慢,問題終于找到了,而且非常符合問題的特點(diǎn),果然把這個(gè)地方換了一種寫法加了2秒鐘超時(shí)的限制,問題沒有再出現(xiàn)。
這次問題的解決過程得出幾點(diǎn)心得:
1、jvm的問題是很復(fù)雜的,通過日志看到的很可能不是問題的根源,解決問題也有運(yùn)氣成分,分析日志+業(yè)務(wù)場景+瞎蒙都是解決問題的方法,分析問題不要一條道走到黑,多結(jié)合當(dāng)前的場景加上一些猜測。
2、這個(gè)問題的根源是CPU飆高,一開始總想著是代碼里有死循環(huán),后來又以為是內(nèi)存泄露,所以走了很多彎路,最后還是用最笨的方法看線程棧的日志看出了問題,所以問題沒有統(tǒng)一的解決方案,具體問題都要具體處理的,不能拘泥于以往的經(jīng)驗(yàn)。
3、在寫代碼過程中盡量使用原項(xiàng)目中已經(jīng)被廣泛使用的公共工具類,盡量不要把自己自創(chuàng)的沒有經(jīng)過項(xiàng)目檢驗(yàn)的代碼引入工程,即使看起來很簡單的一段代碼可能給項(xiàng)目引入災(zāi)難,除非你有充足的把握了解你代碼的底層,比如這個(gè)超時(shí)的設(shè)置問題。
總結(jié)
以上是生活随笔為你收集整理的jvm 崩溃日志设置_记一次JVM疯狂GC导致CPU飙高的问题解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2008 r2彻底删除 server s
- 下一篇: pyqt界面屏幕分辨率自适应_后台系统界