常見命令
#按照進程名字查找
ps -aux | grep java
#強制殺死進程
kill -9 pid
#按照端口號進行查找
netstat -anp |grep 8080
#查看兩個機器是否聯(lián)通
telnet ip 端口
#查看開放的端口
cat /etc/ssh/sshd_config
#跨服務(wù)器拷貝
scp -r xxx.jar root@ssh ip:/usr -》root指的是ip所在的登錄用戶
scp -P 22222 -r xxx.jar root@ssh ip:/usr -》指定端口號默認(rèn)22
scp -r xxx.jar root@ip:/usr -》省略寫ssh
#無日志輸出
nohup java -jar xxx.jar > /dev/null 2> /dev/null &
#有日志輸出
nohup java -jar xxx.jar > ./output.log &
#指定配置文件輸出
nohup java -jar xxx.jar --spring.profiles.active=test2> ./output.log &
#查看日志
tail -f ./output.log
#復(fù)雜搜索
grep
定位
grep '搜索內(nèi)容' 路徑開頭* ->比如grep 'aa' ./*xxx.log 或者xxx*或者xxx.log
搜索內(nèi)容復(fù)雜的可以用右邊替換 \\[projectName\\][[:space:]]is System* ->英文中括號加反斜杠,空格用[[:space:]]替換寞缝,搜索內(nèi)容不要加引號
前后
grep -C 100 '搜索內(nèi)容' xxx* 搜索前后100行
grep -A 10 -B 1 '搜索內(nèi)容' xxx* 搜索前一行后10行
tail
tail -10f xxx.log 指定整個文件
1癌压、死鎖
#性能排查
https://blog.csdn.net/weixin_45549188/article/details/129629486
#arthas教程
https://arthas.aliyun.com/doc/quick-start.html
/**
//54-死鎖
*/
// 創(chuàng)建兩個共享資源
private static final String resource1 = new String();
private static final Object resource2 = new Object();
@GetMapping("lock")
public void lock() {
/**
* 兩個線程 thread1 thread2
* thread1對resource1上鎖,然后嘗試獲取resource2的鎖荆陆;
* thread2對resource2上鎖滩届,然后嘗試獲取resource1的鎖;
* 2個線程會相互等待被啼,出現(xiàn)死鎖
*/
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("Thread 1: Locked resource 1");
try {
Thread.sleep(100); // 假設(shè)這里有其他操作帜消,需要一些時間
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Thread 1: Attempting to lock resource 2");
//嘗試索取resource2的鎖
synchronized (resource2) {
System.out.println("Thread 1: Locked resource 2");
}
}
}, "thread1");
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("Thread 2: Locked resource 2");
try {
Thread.sleep(100); // 假設(shè)這里有其他操作,需要一些時間
} catch (Exception e) {
e.printStackTrace();
}
//嘗試索取resource1的鎖
System.out.println("Thread 2: Attempting to lock resource 1");
synchronized (resource1) {
System.out.println("Thread 2: Locked resource 1");
}
}
}, "thread2");
// 啟動線程
thread1.start();
thread2.start();
}
1-1浓体、【推薦】排查步驟(命令)方法1
ps -aux | grep java
#殺死進程繼續(xù)下一個測試
kill -9 pid
#以守護進程啟動
nohup java -jar cpu-oom-test-1.0-SNAPSHOT.jar > ./output.log &
#如果出現(xiàn)這個工具沒有的話
-bash: pstack: command not found
sudo yum install -y gdb
#直接輸入面程序查看死鎖
top
jstack pid
image.png
最后面就會出現(xiàn)發(fā)生死鎖的位置了(默認(rèn)敲完jstack命令就會滑到最后所以很容易就看到了)
image.png
1-2泡挺、使用arthas->方法2
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
#輸入你的java程序,回車
#直接輸入面程序查看死鎖
thread -b
image.png
image.png
2汹碱、內(nèi)存泄漏
/**
//55-內(nèi)存泄露
*/
public static List<byte[]> oomList = new ArrayList<>();
@GetMapping("oom")
public String oom() {
while (true) {
//不斷向列表中添加大對象, 10MB
oomList.add(new byte[1024 * 1024 * 10]);
}
}
//55-內(nèi)存泄露
ps -aux | grep java
#殺死進程繼續(xù)下一個測試
kill -9 pid
#以守護進程啟動
nohup java -jar cpu-oom-test-1.0-SNAPSHOT.jar > ./output.log &
top
#可以查看內(nèi)存占用情況
jmap -heap pid
#使用arthas查看占用情況
dashboard
image.png
image.png
2-1【推薦】使用程序運行日志直接查看
這時候其實output.log里面也能看見是哪一行泄漏的
grep -A 10 -B 1 'OutOfMemory' output.log
image.png
2-2程序在運行之前就指定dump輸出(特點文件小粘衬,信息精準(zhǔn))
運行直接指定(設(shè)置內(nèi)存比較小方便測試)
nohup java -jar -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap-dump.hprof -Xmx10m xxx.jar > ./output.log &
#將上面的dump文件考出來
#用visualvm工具進行分析,沒有的進行下載
https://visualvm.github.io/index.html
用工具加載之后咳促,首頁就有泄漏的紅色標(biāo)記
或者summary換成thread 視圖選擇文本直接搜memory就可以看到了
image.png
image.png
2-3 在運行的時候手動導(dǎo)出堆信息(特點文件大稚新,沒有直接溢出信息)【不推薦】
#在運行導(dǎo)出日志文件【直接導(dǎo)出的文件大,而且查不見泄漏的進程跪腹,日志可以】
jmap -dump:format=b,file=./dump.hprof pid
#將上面的dump文件考出來
https://eclipse.dev/mat/
#必須使用Eclipse MAT工具進行分析才行
(工具下載不下來換鏡像褂删,jdk必須17以上)
#Spring推薦的Liberica Open JDK下載地址-貝爾實驗室版本
https://bell-sw.com/pages/downloads/#jdk-8-lts
image.png
往下滑會提示有提示,只能大致推斷出是那個類冲茸,不能具體到哪一行
Thread Stack信息里面顯示也是空空如也
image.png
image.png
如果結(jié)合visualvm分析的話屯阀,只能說也很難推斷出是哪一行吧缅帘,不推薦
image.png
image.png
3、cpu飆升
/**
//56-cpu飆升
//常規(guī)排查和arthas-57
*/
@GetMapping("cpu")
public void test1() {
System.out.println("程序已啟動");
while (true) {
;
}
}
3-1常規(guī)方法(方法1)
ps -aux | grep java
#殺死進程繼續(xù)下一個測試
kill -9 pid
#以守護進程啟動
nohup java -jar cpu-oom-test-1.0-SNAPSHOT.jar > ./output.log &
#使用top命令找到cpu飆升進程id
top
#根據(jù)進程id找到導(dǎo)致cpu飆升的線程
ps H -eo pid,tid,%cpu | grep 進程id
#將線程id轉(zhuǎn)換為16進制
printf '0x%x\n' 線程id
#根據(jù)線程定位問題代碼
jstack 進程id | grep 16進制線程id -A 20
image.png
image.png
image.png
image.png
簡化【推薦难衰,省事】
創(chuàng)建一個腳本直接執(zhí)行钦无,把上面幾個步驟合起來
#!/bin/bash
# 獲取用戶輸入的進程 ID
read -p "請輸入要分析的Java進程ID: " pid
# 查找該進程下CPU使用率最高的線程(按CPU使用率降序排序取第一條)
top_thread=$(ps H -eo pid,tid,%cpu | grep $pid | sort -k3 -nr | head -n 1 | awk '{print $2}')
# 將線程ID轉(zhuǎn)換為十六進制
hex_thread=$(printf '0x%x\n' $top_thread)
# 使用jstack查找對應(yīng)線程的棧信息并輸出
jstack $pid | grep $hex_thread -A 20
image.png
3-2使用arthas(方法2)【推薦快】
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
#輸入你的java程序,回車
thread
#找到占用最高cpu的線程id
thread 線程id
image.png
image.png
4盖袭、arthas排查接口響應(yīng)慢失暂,代碼不生效,方法執(zhí)行異常
/**
//58-60-接口響應(yīng)慢-arthas
*/
@GetMapping("slow")
public void slow() throws InterruptedException {
log.info("start");
this.m1(100, "t1");
this.m1(200, "t2");
this.m1(1000, "t3");
log.info("end");
}
private void m1(int minus, String name) throws InterruptedException {
//休眠100毫秒
TimeUnit.MILLISECONDS.sleep(minus);
log.info(name);
}
ps -aux | grep java
#殺死進程繼續(xù)下一個測試
kill -9 pid
#以守護進程啟動
nohup java -jar cpu-oom-test-1.0-SNAPSHOT.jar > ./output.log &
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
#輸入你的java程序鳄虱,回車
4-1排查接口響應(yīng)慢
#接口響應(yīng)慢排查
【會顯示總共執(zhí)行時間是多少毫秒弟塞,每個步驟是多少毫秒】
trace com.csw.cpuoom.controller.CpuOomController slow -n 5 --skipJDKMethod false
然后再掉一下接口觀察輸出
image.png
image.png
4-2、代碼未生效
#檢查代碼未生效
【會反編譯類獲取線上的代碼拙已,能看到線上代碼對不對】
jad com.csw.cpuoom.controller.CpuOomControllerjadd
image.png
4-3方法執(zhí)行異常(執(zhí)行結(jié)果)
/**
62-查看方法執(zhí)行異常-atthas
*/
@GetMapping("err")
public void err() throws InterruptedException {
System.out.println("程序已啟動");
for (int i = 1; i < 1000000; i++) {
add(i, i + 1);
TimeUnit.SECONDS.sleep(1);
}
}
public static int add(int a, int b) {
return a + b;
}
#檢查方法執(zhí)行異常(執(zhí)行結(jié)果)
【相當(dāng)于說能夠看到方法的實時請求和返回值】【先敲命令后掉接口】
watch com.csw.cpuoom.controller.CpuOomController add "{params,returnObj}" -x 2 -n 999
image.png
image.png