開發與維運

Arthas 實踐——生產環境排查 CPU 飈高問題

作者 | 李昊(可以養肥)

【Arthas 官方社區正在舉行徵文活動,參加即有獎品拿~點擊投稿

生產環境 CPU 告警:

 13:40 收到我們的生產環境服務器綠版 CUP 超負載告警通知。

1.png

此時心裡只有一個想法,重啟大法好,馬上登錄服務器,執行 top 發現進程 30247 和 28337 佔用 CPU 為 200 多和100 多基本佔用了 4 核的 3 核,整個過程大概用時 30 秒,維護群依然很平靜,運營的電話也沒打過來,這時候我斷定,這次問題應該影響面很小,用戶可能也暫時沒有發現,好吧,還有時間做排查。

2.png

Arthas排查過程:

  • 開啟 Arthas 工具找到對應的 30247 運單模塊和 28337 支付模塊,選擇運單模塊進入:
java -jar arthas-boot.jar

3.png

  • 執行 dashboard 命令,線程 35 和 12042 不正常 CUP 佔用 49%:
dashboard

4.png

  • 執行 thread 35  thread 12042 定位代碼行:
thread 35
thread 12042

5.png

  • 查看代碼,業務需求為生成一個至少包含 2 個數字的隨機字符串,我們使用的統一的工具類方法,該方法中先通過 UUID.randomUUID() 隨機出一個 10 位的字符池,然後再從這個字符池中隨機需要位數的字符串,如果隨機出來的 10 位字符池中都是字母,則二次隨機時候就會出現死循環,問題代碼如下:
public static String getRandomStr(boolean numberFlag, int length) {
    String retStr = "";
    String strTable =
        numberFlag
            ? UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10)
            : "1234567890abcdefghijkmnpqrstuvwxyz";
    int len = strTable.length();
    boolean bDone = true;
    do {
      retStr = "";
      int count = 0;
      for (int i = 0; i < length; i++) {
        double dblR = Math.random() * len;
        int intR = (int) Math.floor(dblR);
        char c = strTable.charAt(intR);
        if (('0' <= c) && (c <= '9')) {
          count++;
        }
        retStr += strTable.charAt(intR);
      }
      if (count >= 2) {
        bDone = false;
      }
    } while (bDone);
    return retStr;
  }
  • 線下模擬不到二萬次 UUID.randomUUID() 前十位會出現一次全字母的情況。

6.png

  • 最終原因是死循環導致的 CPU 飈高,修復代碼,增加是否都是字母的判斷,第一次隨機出來的 10 位字符池都是字母,則重新隨機。

Arthas 常用命令:

安裝

curl -O arthas.aliyun.com/arthas-boot…
java -jar arthas-boot.jar

基礎命令

help——查看命令幫助信息
cat——打印文件內容,和 linux 裡的 cat 命令類似
echo–打印參數,和 linux 裡的 echo 命令類似
grep——匹配查找,和 linux 裡的 grep 命令類似
tee——複製標準輸入到標準輸出和指定的文件,和 linux 裡的 tee 命令類似
pwd——返回當前的工作目錄,和 linux 命令類似
cls——清空當前屏幕區域
session——查看當前會話的信息
reset——重置增強類,將被 Arthas 增強過的類全部還原,Arthas 服務端關閉時會重置所有增強過的類
version——輸出當前目標 Java 進程所加載的 Arthas 版本號
history——打印命令歷史
quit——退出當前 Arthas 客戶端,其他 Arthas 客戶端不受影響
stop——關閉 Arthas 服務端,所有 Arthas 客戶端全部退出
keymap——Arthas 快捷鍵列表及自定義快捷鍵

jvm相關

dashboard——當前系統的實時數據面板
thread——查看當前 JVM 的線程堆棧信息
jvm——查看當前 JVM 的信息
sysprop——查看和修改 JVM 的系統屬性
sysenv——查看 JVM 的環境變量
vmoption——查看和修改 JVM 裡診斷相關的 option
perfcounter——查看當前 JVM 的 Perf Counter 信息
logger——查看和修改 logger
getstatic——查看類的靜態屬性
ognl——執行 ognl 表達式
mbean——查看 Mbean 的信息
heapdump——dump java heap, 類似 jmap 命令的 heap dump 功能

class/classloader相關

sc——查看 JVM 已加載的類信息
sm——查看已加載類的方法信息
jad——反編譯指定已加載類的源碼
mc——內存編譯器,內存編譯 .java 文件為 .class 文件
redefine——加載外部的 .class 文件,redefine 到 JVM 裡
dump——dump 已加載類的 byte code 到特定目錄
classloader——查看 classloader 的繼承樹,urls,類加載信息,使用 classloader 去 getResource

monitor/watch/trace相關

  • monitor 方法執行監控

monitor -c 5 demo.MathGame primeFactors

-c 5 未統計週期默認 120s

  • watch 能觀察到的範圍為:返回值、拋出異常、入參

watch demo.MathGame primeFactors “{params,target,returnObj}” -x 2 -b -s -n 2

-x 2 輸出結果的屬性遍歷深度
-b 方法調用前
-s 方法返回後
-n 2 執行2次

watch demo.MathGame primeFactors “{params[0],throwExp}” -e -x 2

-e表示拋出異常時才觸發

  • trace 方法內部調用路徑,並輸出方法路徑上的每個節點上耗時

trace demo.MathGame run

Arthas 徵文活動火熱進行中

Arthas 官方正在舉行徵文活動,如果你有:

  • 使用 Arthas 排查過的問題
  • 對 Arthas 進行源碼解讀
  • 對 Arthas 提出建議
  • 不限,其它與 Arthas 有關的內容

歡迎參加徵文活動,還有獎品拿哦~點擊投稿

Leave a Reply

Your email address will not be published. Required fields are marked *