自写自查CPU过高问题

自写自查CPU过高问题

1、问题

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

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

2.1、准备文件内容

创建目录

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

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

image-20220527092937297

文件内容如下:

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

image-20220527093915001

查看镜像信息

[~]$ 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

image-20220527095853072

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

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

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

image-20220527100121565

此时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

image-20220527100905125

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

image-20220527101857416

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

5、解决问题

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

6、回答问题

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

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

6、结束语

删除构造问题的镜像

[~]$ docker rmi java-test

image-20220527094450858

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

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

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

[~]$ docker logs <容器id>
posted @   码出新生活!  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示