經過jstack與jmap分析一次線上故障

1、發現問題

  下面是線上機器的cpu使用率,能夠看到從4月8日開始,隨着時間cpu使用率在逐步增高,最終使用率達到100%致使線上服務不可用,後面重啓了機器後恢復。java

2、排查思路 

簡單分析下可能出問題的地方,分爲5個方向:tomcat

1.系統自己代碼問題eclipse

2.內部下游系統的問題致使的雪崩效應tcp

3.上游系統調用量突增ide

4.http請求第三方的問題線程

5.機器自己的問題3d

3、開始排查 

1.查看日誌,沒有發現集中的錯誤日誌,初步排除代碼邏輯處理錯誤。日誌

2.首先聯繫了內部下游系統觀察了他們的監控,發現一塊兒正常。能夠排除下游系統故障對咱們的影響。orm

3.查看provider接口的調用量,對比7天沒有突增,排除業務方調用量的問題。對象

4.查看tcp監控,TCP狀態正常,能夠排除是http請求第三方超時帶來的問題。

5.查看機器監控,6臺機器cpu都在上升,每一個機器狀況同樣。排除機器故障問題。

  即經過上述方法沒有直接定位到問題。

4、解決方案

1.重啓了6臺中問題比較嚴重的5臺機器,先恢復業務。保留一臺現場,用來分析問題。

2.查看當前的tomcat線程pid

3.查看該pid下線程對應的系統佔用狀況。top -Hp 384

4.發現pid 4430 4431 4432 4433 線程分別佔用了約40%的cpu

5.將這幾個pid轉爲16進制,分別爲114e 114f 1150 1151

6.下載當前的java線程棧  sudo -u tomcat jstack -l 384>/1.txt

7.查詢5中對應的線程狀況,發現都是gc線程致使的

8.dump java堆數據

sudo -u tomcat jmap -dump:live,format=b,file=/dump201612271310.dat 384

9.使用MAT加載堆文件,能夠看到javax.crypto.JceSecurity對象佔用了95%的內存空間,初步定位到問題。

MAT下載地址:http://www.eclipse.org/mat/

10.查看類的引用樹,看到BouncyCastleProvider對象持有過多。即咱們代碼中對該對象的處理方式是錯誤的,定位到問題。

 

5、代碼分析

咱們代碼中有一塊是這樣寫的

這是加解密的功能,每次運行加解密都會new一個BouncyCastleProvider對象,放倒Cipher.getInstance()方法中。

看下Cipher.getInstance()的實現,這是jdk的底層代碼實現,追蹤到JceSecurity類中

verifyingProviders每次put後都會remove,verificationResults只會put,不會remove.

看到verificationResults是一個static的map,即屬於JceSecurity類的。

因此每次運行到加解密都會向這個map put一個對象,而這個map屬於類的維度,因此不會被GC回收。這就致使了大量的new的對象不被回收。

6、代碼改進

將有問題的對象置爲static,每一個類持有一個,不會屢次新建。

7、本文總結

遇到線上問題不要慌,首先確認排查問題的思路:

  1. 查看日誌
  2. 查看CPU狀況
  3. 查看TCP狀況
  4. 查看java線程,jstack
  5. 查看java堆,jmap
  6. 經過MAT分析堆文件,尋找沒法被回收的對象
相關文章
相關標籤/搜索