自寫自查CPU過高問題
阿新 • • 發佈:2022-05-27
自寫自查CPU過高問題
目錄1、問題
說一說線上CPU過高怎麼辦?
2、製造問題(通過docker方式)
2.1、準備檔案內容
建立目錄
[~]$ cd /
[~]$ mkdir /app
[~]$ cd ~
[~]$ mkdir cpuTestDir
[~]$ vi dockerfile
輸入快捷鍵 i 指令,編寫dockerfile
檔案
檔案內容如下:
# 基於java 9 FROM java:9 # 設定工作目錄 WORKDIR /app # 複製檔案到工作目錄 COPY . /app # 設定java環境變數 ENV PATH=$PATH:$JAVA_HOME/bin ENV JRE_HOME=${JAVA_HOME}/jre ENV CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib # 編譯 RUN ["/usr/lib/jvm/java-9-openjdk-amd64/bin/javac","CPUTest.java"] # 執行 ENTRYPOINT ["/usr/lib/jvm/java-9-openjdk-amd64/bin/java","CPUTest"]
執行快捷指令(英文模式下輸入):
- esc
- shift + :
- wq
按照上述方法,在當前目錄建立CPUTest.java
檔案,檔案內容如下:
import java.math.BigInteger; /** * @author lishanbiao * @date 2022/5/27 7:27 上午 */ public class CPUTest { public static void main(String[] args) throws InterruptedException { new Thread(() -> { BigInteger i = new BigInteger("1"); BigInteger j = new BigInteger("1"); while (true) { i.add(j); } }).start(); Thread.sleep(100000000); } }
執行命令檢視:
[~]$ ls
CPUTest.java dockerfile
2.2、構建映象
[~]$ docker build . -f dockerfile -t java-test:latest
檢視映象資訊
[~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
java-test latest b44aa1a44e4d 17 seconds ago 579MB
執行映象
[~]$ docker run -itd java-test:latest
Options | Mean |
---|---|
-i | 以互動模式執行容器,通常與 -t 同時使用; |
-t | 為容器重新分配一個偽輸入終端,通常與 -i 同時使用; |
-d | 後臺執行容器,並返回容器ID; |
檢視執行中的容器
[~]$ docker ps
進入執行中的容器
[~]$ docker exec -it 728b98b3b581 /bin/bash
root@728b98b3b581:/app#
執行java程式
root@728b98b3b581:/app# ls
CPUTest.class CPUTest.java dockerfile
root@728b98b3b581:/app# java CPUTest
執行成功……
使用快捷鍵:ctrl + c
中斷終端(此時java程式已經在執行)
3、排查問題
root@728b98b3b581:/app# top
找到cpu佔用率高的程序id(pid),然後執行q快捷鍵指令退出,之後執行指令
root@728b98b3b581:/app# top -p 1
Shift + h
使用快捷鍵顯示程序下所有執行緒
此時cpu最高的pid就是執行緒所對應的執行緒id(tid,spid,lwf)
轉換為16進位制
root@728b98b3b581:/app# printf "%0x\n" 17
11
此時利用java自帶的檢視執行緒命令檢視該執行緒的執行狀況:jstack <pid> | grep -A 10 <Thread 0x16 id>
root@728b98b3b581:/app# jstack 1 | grep -A 10 11
此時我們可以找到問題所在:CPUTest.java:13
java.lang.Thread.State: RUNNABLE
at CPUTest.lambda$main$0(CPUTest.java:13)
at CPUTest$$Lambda$1/1018547642.run(Unknown Source)
at java.lang.Thread.run(java.base@9-Debian/Thread.java:844)
4、定位問題
這個時候,為了找到java
對應的執行緒執行原始碼,我們先退出容器
root@728b98b3b581:/app# exit
exit
[root@node1 ~]#
定位原始碼
[root@node1 ~]# cd cpuProblemByDocker/
[root@node1 cpuProblemByDocker]# ls
CPUTest.java dockerfile
[root@node1 cpuProblemByDocker]# cat -n CPUTest.java
1 import java.math.BigInteger;
2
3 /**
4 * @author lishanbiao
5 * @date 2022/5/27 7:27 上午
6 */
7 public class CPUTest {
8 public static void main(String[] args) throws InterruptedException {
9 new Thread(() -> {
10 BigInteger i = new BigInteger("1");
11 BigInteger j = new BigInteger("1");
12 while (true) {
13 i.add(j);
14 }
15 }).start();
16 System.out.println("執行成功……");
17 Thread.sleep(100000000);
18 }
19 }
20
[root@node1 cpuProblemByDocker]#
我們最終發現了存在問題的第13
行,原來是一個死迴圈!
5、解決問題
如果這是真實發生的問題,請及時解決,我這裡是構造的問題,所以不用那麼麻煩啦~
6、回答問題
線上CPU過高可能是因為某些執行緒陷入死迴圈導致的,我們可以按照如下步驟排查:
- top:找到cpu佔用率高的java程序id(pid)
- shift + h:找到程序下所有執行緒資訊(執行緒id、執行緒所佔用的cpu使用率)
- printf "%0x\n" <pid>:記住執行緒id並轉換為16進位制形式
- jstack <pid> | grep -A 10 <Thread 0x16 id>:利用java的jstack 檢視java執行緒的資訊
- cat -n file:檢視找到該執行緒執行到的原始碼資訊
- 解決問題
6、結束語
刪除構造問題的映象
[~]$ docker rmi java-test
製造問題過程中遇到其他命令和快捷鍵
- gg:定位到檔案首部
- dG:清空游標位置到末尾的檔案內容
檢視正在執行的容器終端列印日誌
[~]$ docker logs <容器id>