转载

线上故障排查(1) - Java应用故障之高CPU占用的问题及排查方案

做为应用负责人,谁都希望自己负责的应用能够在线上跑得顺顺当当,不出任何错误,也不产生任何告警,当然这是最理想的结果,也是做为技术人员希望达到的最终效果。可是实事上应用就像小孩一样,总会在不经意间,不按你期望的结果运行,如CPU偏高、内存占用偏高、应用没有响应、应用自动挂掉等,搞得我们技术人员不是一般的头大。我本人虽然身处管理岗位,也是处理在技术的第一线,也曾碰到过各种各样的奇奇怪怪的问题,在此记录下来,分享给给大家,今天第一篇分享是关于如何排查CPU偏高的问题。

以下是一段简易的测试代码,用于模拟应用的CPU占用偏高:

public class CpuUseTest {

    public static void main(String[] args) {
        new Thread() {

            public void run() {
                int result = 0;
                while (true) {
                    result++;
                    if (result > Integer.MAX_VALUE / 2) {
                        result = 0;
                    }
                }
            }
        }.start();        
    }
}

大家应该都知道,单个CPU在同一时刻只能够执行一个线程,如果某个线程一直无限的循环下去,其对这个CPU的占用就不会释放,会把这个CPU给占满,其它线程无法使用,如果电脑是单核的,那么这个时候就会感觉到明显的卡顿。

把这个应用给运行起来后,可以通过TOP命令查看到其CPU的占用情况如下:

线上故障排查(1) - Java应用故障之高CPU占用的问题及排查方案

可以看到其CPU占用率达到了100%,这个时候我们当然希望找出这个CPU占用偏高的代码位置,只有这样我们才能够解决这个问题。首先我们需要理解,Java是一个多线程应用,进程是由多个线程构成的,我们当前看到的是这个是这个进程的CPU占用率,因而导致这个进程CPU偏高的是其中某个或某几个线程,因而我们如果能够找到这些线程那解决问题就好办了。

在Linux环境下,可以通过ps命令(ps命令的详细使用,请通过man ps命令获取更多的帮助)查看指定进程的线程情况,如下指令:

ps -mp 26541 -o THREAD,tid,time

可以查看应用ID为26541的这个Java应用中,线程的CPU使用情况,结果如下:

线上故障排查(1) - Java应用故障之高CPU占用的问题及排查方案

可以看到进程号26541对应的线程tid为26561的线程,CPU占用率达到了99.9%,因而我们只需要找出这个线程目前正在做的事情,那就好解决问题了。Java的JDK中有包括对应的线程堆栈查看工具jstack,根据找到的线程ID 26561,就可以定位到CPU偏高的问题了。

注:通过ps命令查看到的线程ID 26561是十进制,在有的Java JDK里面的jstack命令输出的是十进制的线程ID,有的是十六进制的线程ID,这个需要使用者先通过jstack命令去查看了,如果是十六进制的线程ID,可以通过如下命令将十进制的线程ID转换为十六进程的线程ID,如这里将线程ID 26561转换为十六进制的命令如下:

fenglibin@fenglibin-HP:/home/fenglibin$ printf "%x/n" 26561
67c1

这里得到的线程ID的十六进制就是67c1,我的电脑中的jstack显示的线程号是十六进制的,因而就使用这个十六制了。通过如下命令可以找到导致当前应用CPU偏高的线程和其执行堆栈:

线上故障排查(1) - Java应用故障之高CPU占用的问题及排查方案

可以看到导致该线程CPU偏高的执行堆栈为测试代码中的第18行,也就是执行无限循环的代码块所在的位置,直此导致该应用CPU偏高的问题,被成功定位。

后续我们继续写如何定位内存溢出的问题,如果感兴趣,可以继续观注。

原文  https://blog.csdn.net/fenglibing/article/details/82690174
正文到此结束
Loading...