最牛逼的故障診斷工具!秒級定位線上問題
往期熱門文章:
1、新技能 MyBatis 千萬數(shù)據(jù)表,快速分頁! 2、常見的SQL面試題:經(jīng)典50例 3、事務(wù)注解 @Transactional 失效的3種場景及解決辦法 4、看看人家SpringBoot的全局異常處理多么優(yōu)雅... 5、代碼總是被嫌棄寫的太爛?裝上這個(gè)IDEA插件再試試!
背景

1. top oder by with P:1040 // 首先按進(jìn)程負(fù)載排序找到 axLoad(pid)
2. top -Hp 進(jìn)程PID:1073 // 找到相關(guān)負(fù)載 線程PID
3. printf “0x%x\n”線程PID: 0x431 // 將線程PID轉(zhuǎn)換為 16進(jìn)制,為后面查找 jstack 日志做準(zhǔn)備
4. jstack 進(jìn)程PID | vim +/十六進(jìn)制線程PID - // 例如:jstack 1040|vim +/0x431 -
快速安裝使用:
source <(curl -fsSL https://raw.githubusercontent.com/oldratlee/useful-scripts/master/test-cases/self-installer.sh)
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexLoad {
public static void main(String[] args) {
String[] patternMatch = {"([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)",
"([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)+([+\\-/*])+([\\w\\s]+)"};
List patternList = new ArrayList();
patternList.add("Avg Volume Units product A + Volume Units product A");
patternList.add("Avg Volume Units / Volume Units product A");
patternList.add("Avg retailer On Hand / Volume Units Plan / Store Count");
patternList.add("Avg Hand Volume Units Plan Store Count");
patternList.add("1 - Avg merchant Volume Units");
patternList.add("Total retailer shipment Count");
for (String s :patternList ){
for(int i=0;i<patternmatch.length;i++){
Pattern pattern = Pattern.compile(patternMatch[i]);
Matcher matcher = pattern.matcher(s);
System.out.println(s);
if (matcher.matches()) {
System.out.println("Passed");
}else
System.out.println("Failed;");
}
}
}
}

怎么使用呢?
show-busy-java-threads.sh
# 從 所有的 Java進(jìn)程中找出最消耗CPU的線程(缺省5個(gè)),打印出其線程棧。
show-busy-java-threads.sh -c <要顯示的線程棧數(shù)>
show-busy-java-threads.sh -c <要顯示的線程棧數(shù)> -p <指定的Java Process>
# -F選項(xiàng):執(zhí)行jstack命令時(shí)加上-F選項(xiàng)(強(qiáng)制jstack),一般情況不需要使用
show-busy-java-threads.sh -p <指定的Java Process> -F
show-busy-java-threads.sh -s <指定jstack命令的全路徑>
# 對于sudo方式的運(yùn)行,JAVA_HOME環(huán)境變量不能傳遞給root,
# 而root用戶往往沒有配置JAVA_HOME且不方便配置,
# 顯式指定jstack命令的路徑就反而顯得更方便了
show-busy-java-threads.sh -a <輸出記錄到的文件>
show-busy-java-threads.sh -t <重復(fù)執(zhí)行的次數(shù)> -i <重復(fù)執(zhí)行的間隔秒數(shù)>
# 缺省執(zhí)行一次;執(zhí)行間隔缺省是3秒
##############################
# 注意:
##############################
# 如果Java進(jìn)程的用戶 與 執(zhí)行腳本的當(dāng)前用戶 不同,則jstack不了這個(gè)Java進(jìn)程。
# 為了能切換到Java進(jìn)程的用戶,需要加sudo來執(zhí)行,即可以解決:
sudo show-busy-java-threads.sh
work@dev_zz_Master 10.48.186.32 23:45:50 ~/demo >
bash show-busy-java-threads.sh
[1] Busy(96.2%) thread(8577/0x2181) stack of java process(8576) under user(work):
"main" prio=10 tid=0x00007f0c64006800 nid=0x2181 runnable [0x00007f0c6a64a000]
java.lang.Thread.State: RUNNABLE
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4168)
at java.util.regex.Pattern$Loop.match(Pattern.java:4295)
...
at java.util.regex.Matcher.match(Matcher.java:1127)
at java.util.regex.Matcher.matches(Matcher.java:502)
at RegexLoad.main(RegexLoad.java:27)
[2] Busy(1.5%) thread(8591/0x218f) stack of java process(8576) under user(work):
"C2 CompilerThread1" daemon prio=10 tid=0x00007f0c64095800 nid=0x218f waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
[3] Busy(0.8%) thread(8590/0x218e) stack of java process(8576) under user(work):
"C2 CompilerThread0" daemon prio=10 tid=0x00007f0c64093000 nid=0x218e waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
[4] Busy(0.2%) thread(8593/0x2191) stack of java process(8576) under user(work):
"VM Periodic Task Thread" prio=10 tid=0x00007f0c640a2800 nid=0x2191 waiting on condition
[5] Busy(0.1%) thread(25159/0x6247) stack of java process(25137) under user(work):
"VM Periodic Task Thread" prio=10 tid=0x00007f13340b4000 nid=0x6247 waiting on condition
work@dev_zz_Master 10.48.186.32 23:46:04 ~/demo >
import java.util.*;
public class SimpleDeadLock extends Thread {
public static Object l1 = new Object();
public static Object l2 = new Object();
private int index;
public static void main(String[] a) {
Thread t1 = new Thread1();
Thread t2 = new Thread2();
t1.start();
t2.start();
}
private static class Thread1 extends Thread {
public void run() {
synchronized (l1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (l2) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
private static class Thread2 extends Thread {
public void run() {
synchronized (l2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (l1) {
System.out.println("Thread 2: Holding lock 2 & 1...");
}
}
}
}
}

如何用工具定位

免費(fèi)實(shí)用的腳本工具大禮包
(1)show-duplicate-java-classes
# 查找當(dāng)前目錄下所有Jar中的重復(fù)類
show-duplicate-java-classes
# 查找多個(gè)指定目錄下所有Jar中的重復(fù)類
show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2
# 查找多個(gè)指定Class目錄下的重復(fù)類。Class目錄 通過 -c 選項(xiàng)指定
show-duplicate-java-classes -c path/to/class_dir1 -c /path/to/class_dir2
# 查找指定Class目錄和指定目錄下所有Jar中的重復(fù)類的Jar
show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 -c path/to/class_dir1 -c path/to/class_dir2
例如:
# 在war模塊目錄下執(zhí)行,生成war文件
$ mvn install
...
# 解壓war文件,war文件中包含了應(yīng)用的依賴的Jar文件
$ unzip target/*.war -d target/war
...
# 檢查重復(fù)類
$ show-duplicate-java-classes -c target/war/WEB-INF/classes target/war/WEB-INF/lib
...
(2)find-in-jars
find-in-jars 'log4j\.properties'
find-in-jars 'log4j\.xml$' -d /path/to/find/directory
find-in-jars log4j\\.xml
find-in-jars 'log4j\.properties|log4j\.xml'
$ ./find-in-jars 'Service.class$'
./WEB-INF/libs/spring-2.5.6.SEC03.jar!org/springframework/stereotype/Service.class
./rpc-benchmark-0.0.1-SNAPSHOT.jar!com/taobao/rpc/benchmark/service/HelloService.class
(3)housemd pid [java_home]
查看加載類 跟蹤方法 查看環(huán)境變量 查看對象屬性值 詳細(xì)信息請參考: https://github.com/CSUG/HouseMD/wiki/UserGuideCN
(4)jvm pid
========線程相關(guān)=======
1 : 查看占用cpu最高的線程情況
2 : 打印所有線程
3 : 打印線程數(shù)
4 : 按線程狀態(tài)統(tǒng)計(jì)線程數(shù)
========GC相關(guān)=======
5 : 垃圾收集統(tǒng)計(jì)(包含原因)可以指定間隔時(shí)間及執(zhí)行次數(shù),默認(rèn)1秒, 10次
6 : 顯示堆中各代的空間可以指定間隔時(shí)間及執(zhí)行次數(shù),默認(rèn)1秒,5次
7 : 垃圾收集統(tǒng)計(jì)??梢灾付ㄩg隔時(shí)間及執(zhí)行次數(shù),默認(rèn)1秒, 10次
8 : 打印perm區(qū)內(nèi)存情況*會使程序暫停響應(yīng)*
9 : 查看directbuffer情況
========堆對象相關(guān)=======
10 : dump heap到文件*會使程序暫停響應(yīng)*默認(rèn)保存到`pwd`/dump.bin,可指定其它路徑
11 : 觸發(fā)full gc。*會使程序暫停響應(yīng)*
12 : 打印jvm heap統(tǒng)計(jì)*會使程序暫停響應(yīng)*
13 : 打印jvm heap中top20的對象。*會使程序暫停響應(yīng)*參數(shù):1:按實(shí)例數(shù)量排序,2:按內(nèi)存占用排序,默認(rèn)為1
14 : 觸發(fā)full gc后打印jvm heap中top20的對象。*會使程序暫停響應(yīng)*參數(shù):1:按實(shí)例數(shù)量排序,2:按內(nèi)存占用排序,默認(rèn)為1
15 : 輸出所有類裝載器在perm里產(chǎn)生的對象。可以指定間隔時(shí)間及執(zhí)行次數(shù)
========其它=======
16 : 打印finalzer隊(duì)列情況
17 : 顯示classloader統(tǒng)計(jì)
18 : 顯示jit編譯統(tǒng)計(jì)
19 : 死鎖檢測
20 : 等待X秒,默認(rèn)為1
q : exit
進(jìn)入jvm工具后可以輸入序號執(zhí)行對應(yīng)命令
可以一次執(zhí)行多個(gè)命令,用分號";"分隔,如:1;3;4;5;6
每個(gè)命令可以帶參數(shù),用冒號":"分隔,同一命令的參數(shù)之間用逗號分隔,如:
Enter command queue:1;5:1000,100;10:/data1/output.bin
(5)greys[@IP:PORT]
查看加載類,方法信息 查看JVM當(dāng)前基礎(chǔ)信息 方法執(zhí)行監(jiān)控(調(diào)用量,失敗率,響應(yīng)時(shí)間等) 方法執(zhí)行數(shù)據(jù)觀測、記錄與回放(參數(shù),返回結(jié)果,異常信息等) 方法調(diào)用追蹤渲染 詳細(xì)信息請參考: https://github.com/oldmanpushcart/greys-anatomy/wiki
使用sjk對Java診斷、性能排查、優(yōu)化工具 ttop:監(jiān)控指定jvm進(jìn)程的各個(gè)線程的cpu使用情況 jps: 強(qiáng)化版 hh: jmap -histo強(qiáng)化版 gc: 實(shí)時(shí)報(bào)告垃圾回收信息 更多信息請參考: https://github.com/aragozin/jvm-tools
來源:https://my.oschina.net/leejun2005/blog/1524687
最近熱文閱讀:
1、一次線上 JVM 調(diào)優(yōu)實(shí)踐,F(xiàn)ullGC 40 次/天到 10 天一次的優(yōu)化過程 2、新技能 MyBatis 千萬數(shù)據(jù)表,快速分頁! 3、常見的SQL面試題:經(jīng)典50例 4、事務(wù)注解 @Transactional 失效的3種場景及解決辦法 5、看看人家SpringBoot的全局異常處理多么優(yōu)雅... 6、代碼總是被嫌棄寫的太爛?裝上這個(gè)IDEA插件再試試! 7、60個(gè)相見恨晚的神器工具! 8、終于來了,IDEA 2021.1版本正式發(fā)布,完美支持WSL 2 9、面試被問事務(wù)注解 @Transactional 失效怎么解決? 10、CTO 說了,用錯(cuò) @Autowired 和 @Resource 的人可以領(lǐng)盒飯了 關(guān)注公眾號,你想要的Java都在這里
評論
圖片
表情
