自写自查CPU过高问题

自写自查CPU过高问题

1、问题

说一说线上CPU过高怎么办?

2、制造问题(通过docker方式)

2.1、准备文件内容

创建目录

[~]$ cd /
[~]$ mkdir /app
[~]$ cd ~
[~]$ mkdir cpuTestDir
[~]$ vi dockerfile

输入快捷键 i 指令,编写 dockerfile文件

自写自查CPU过高问题

文件内容如下:

基于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

自写自查CPU过高问题

查看镜像信息

[~]$ 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过高问题

找到cpu占用率高的进程id(pid),然后执行q快捷键指令退出,之后执行指令

root@728b98b3b581:/app# top -p 1

Shift + h使用快捷键显示进程下所有线程

自写自查CPU过高问题

此时cpu最高的pid就是线程所对应的线程id(tid,spid,lwf)

转换为16进制

root@728b98b3b581:/app# printf "%0x\n" 17
11

此时利用java自带的查看线程命令查看该线程的运行状况:jstack

root@728b98b3b581:/app# jstack 1 | grep -A 10 11

自写自查CPU过高问题

此时我们可以找到问题所在: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]#

自写自查CPU过高问题

我们最终发现了存在问题的第 13行,原来是一个死循环!

5、解决问题

如果这是真实发生的问题,请及时解决,我这里是构造的问题,所以不用那么麻烦啦~

6、回答问题

线上CPU过高可能是因为某些线程陷入死循环导致的,我们可以按照如下步骤排查:

  1. top:找到cpu占用率高的java进程id(pid)
  2. shift + h:找到进程下所有线程信息(线程id、线程所占用的cpu使用率)
  3. printf “%0x\n”记住线程id并转换为16进制形式
  4. jstack利用java的jstack 查看java线程的信息
  5. cat -n file:查看找到该线程执行到的源码信息
  6. 解决问题

6、结束语

删除构造问题的镜像

[~]$ docker rmi java-test

自写自查CPU过高问题

制造问题过程中遇到其他命令和快捷键

  • gg:定位到文件首部
  • dG:清空光标位置到末尾的文件内容

查看正在运行的容器终端打印日志

[~]$ docker logs

Original: https://www.cnblogs.com/lishanbiaosMark/p/16316680.html
Author: 码出新生活!
Title: 自写自查CPU过高问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/579730/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球