作者 | 李昊(可以養肥)
【Arthas 官方社區正在舉行征文活動,參加即有獎品拿~點擊投稿】
生產環境 CPU 告警:
13:40 收到我們的生產環境服務器綠版 CUP 超負載告警通知。
此時心里只有一個想法,重啟大法好,馬上登錄服務器,執行 top 發現進程 30247 和 28337 占用 CPU 為 200 多和100 多基本占用了 4 核的 3 核,整個過程大概用時 30 秒,維護群依然很平靜,運營的電話也沒打過來,這時候我斷定,這次問題應該影響面很小,用戶可能也暫時沒有發現,好吧,還有時間做排查。
Arthas排查過程:
- 開啟 Arthas 工具找到對應的 30247 運單模塊和 28337 支付模塊,選擇運單模塊進入:
java -jar arthas-boot.jar
- 執行 dashboard 命令,線程 35 和 12042 不正常 CUP 占用 49%:
dashboard
- 執行 thread 35 thread 12042 定位代碼行:
thread 35
thread 12042
- 查看代碼,業務需求為生成一個至少包含 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()
前十位會出現一次全字母的情況。
- 最終原因是死循環導致的 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