Java服務問題快速排查指南

問題

收到服務內存佔用過大告警,登錄虛擬機使用top發現每隔幾秒java進程佔用的CPU就會暴增一次。

排查方向一:服務日誌

  1. 使用tail -fn 100 xxx.log查看服務日誌,發現頻繁打印連接mail服務器失敗錯誤,根據錯誤堆棧信息定位到業務代碼位置
  2. 定位業務代碼中的錯誤

排查方向二:JVM工具

若代碼中未打印出錯信息,可以考慮從jvm線程上入手。

  1. 使用jps -mlv獲取java服務pid
  2. 使用top -H -p pid查看高佔用線程,CPU打滿時有10多個線程都佔10%左右
  3. 使用jstat -gc pid 1000jstat -gcutil pid 1000查看gc情況,發現大約每隔1到2秒jvm進行一次minor gc,老年代空間幾乎不變,懷疑業務邏輯導致不斷創建、釋放新對象
  4. 記錄步驟2中高佔用率的幾個線程tid,使用printf %x\n tid將tid轉爲16進制
  5. 使用jstack pid打印線程狀態,觀察未出現死鎖,搜索上一步的16進制數對應的線程,發現繁忙線程果真大都是gc線程,同時參雜着自定義線程池的線程,找到running狀態的線程,根據線程調用棧定位到代碼中執行的位置
  6. 業務代碼中線程正在執行的是郵件發送操作,與方向一種錯誤位置吻合
  7. 定位到錯誤根源:該機器未開啓外網訪問權限,而代碼業務邏輯中檢測郵件發送連接失敗則直接扔回隊列中重試,因爲沒有設定最大重試次數導致頻繁創建郵件消息體,耗盡堆空間,打開外網後問題解決

輔助分析
使用jmap -dump:format=b,file=dump.bin pid生成堆轉儲文件,使用jhat dump.bin或複製到有VisualVM等分析工具的機器上進行分析,可以發現佔用堆空間最大的是char[]數組,打開其中幾個發現內容都是一致的,都是郵件發送的消息體。

擴展

  1. 可以結合freevmstatiostatnetstat等系統命令進行分析排查
  2. 將上述步驟寫成腳本方便快速定位問題,網上已有不少例子,如 https://github.com/oldratlee/useful-scripts
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章