线上应用故障排查之一:高CPU占用

一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。

以我们最近出现的一个实际故障为例,介绍怎么定位和解决这类问题。

根据top命令,发现PID为28555的Java进程占用CPU高达200%,出现故障。

通过ps aux | grep PID命令,可以进一步确定是tomcat进程出现了问题。但是,怎么定位到具体线程或者代码呢?

首先显示线程列表:

ps -mp pid -o THREAD,tid,time

找到了耗时最高的线程28802,占用CPU时间快两个小时了!

其次将需要的线程ID转换为16进制格式:

printf "%x\n" tid

最后打印线程的堆栈信息:

jstack pid |grep tid -A 30

找到出现问题的代码了!

现在来分析下具体的代码:ShortSocketIO.readBytes(ShortSocketIO.java:106)

ShortSocketIO是应用封装的一个用短连接Socket通信的工具类。readBytes函数的代码如下:

public byte[] readBytes(int length) throws IOException {
    if ((this.socket == null) || (!this.socket.isConnected())) {
        throw new IOException("++++ attempting to read from closed socket");
    }
    byte[] result = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    if (this.recIndex >= length) {
           bos.write(this.recBuf, 0, length);
           byte[] newBuf = new byte[this.recBufSize];
           if (this.recIndex > length) {
               System.arraycopy(this.recBuf, length, newBuf, 0, this.recIndex - length);
           }
           this.recBuf = newBuf;
           this.recIndex -= length;
    } else {
           int totalread = length;
           if (this.recIndex > 0) {
                totalread -= this.recIndex;
                bos.write(this.recBuf, 0, this.recIndex);
                this.recBuf = new byte[this.recBufSize];
                this.recIndex = 0;
    }
    int readCount = 0;
    while (totalread > 0) { 
         if ((readCount = this.in.read(this.recBuf)) > 0) { 
                if (totalread > readCount) {
                      bos.write(this.recBuf, 0, readCount);
                      this.recBuf = new byte[this.recBufSize];
                      this.recIndex = 0;
               } else {
                     bos.write(this.recBuf, 0, totalread);
                     byte[] newBuf = new byte[this.recBufSize];
                     System.arraycopy(this.recBuf, totalread, newBuf, 0, readCount - totalread);
                     this.recBuf = newBuf;
                     this.recIndex = (readCount - totalread);
             }
             totalread -= readCount;
        }
   }
}

问题就出在标红的代码部分。如果this.in.read()返回的数据小于等于0时,循环就一直进行下去了。而这种情况在网络拥塞的时候是可能发生的。

至于具体怎么修改就看业务逻辑应该怎么对待这种特殊情况了。

最后,总结下排查CPU故障的方法和技巧有哪些:

1、top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。

2、PS命令:Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。

3、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。

4、pstack:Linux命令。可以查看某个进程的当前线程栈运行情况。

时间: 2024-08-19 14:15:32

线上应用故障排查之一:高CPU占用的相关文章

线上应用故障排查之二:高内存占用

搞Java开发的,经常会碰到下面两种异常: 1.java.lang.OutOfMemoryError: PermGen space 2.java.lang.OutOfMemoryError: Java heap space 要详细解释这两种异常,需要简单重提下Java内存模型. Java内存模型是描述Java程序中各变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节. 在Java虚拟机中,内存分为三个代:新生代(New).老生代(Ol

线上应用故障排查之二:高内存占用(转)

搞Java开发的,经常会碰到下面两种异常: 1.java.lang.OutOfMemoryError: PermGen space 2.java.lang.OutOfMemoryError: Java heap space 要详细解释这两种异常,需要简单重提下Java内存模型. (友情提示:本博文章转载,出处:hankchen,http://www.blogjava.net/hankchen) Java内存模型是描述Java程序中各变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统

Java线上应用故障排查之一:高CPU占用

一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. (友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hankchen) 以我们最近出现的一个实际故障为例,介绍怎么定位和解决这类问题. 根据top命令,发现PID为28555的Java进程占用CPU高达200%,出现故障. 通过ps aux | grep PID命令,可以进一步确定是tomcat进程出现了问题.但是,怎么定位到具体线程或者代码呢? 首先显示线

java程序故障排查脚本之——CPU占用高

[email protected]:~/tmp# cat java_Analy.sh #!/bin/bash T=`ps -mp $1 -o THREAD,tid,time|sort -k 2 -nr|awk '{print $2","$8","$9}'|head -n 11|grep -v "-"` for i in $Tdo consum=`echo $i |awk -F"," '{print $1}'` tid=`ech

生产环境下JAVA进程高CPU占用故障排查

问题描述:生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析:1,程序属于CPU密集型,和开发沟通过,排除此类情况.2,程序代码有问题,出现死循环,可能性极大. 问题解决:1,开发那边无法排查代码某个模块有问题,从日志上也无法分析得出.2,记得原来通过strace跟踪的方法解决了一台PHP服务器CPU占用高的问题,但是通过这种方法无效,经过google搜索,发现可以通过下面的方法进行解决,那就尝试下

用“逐步排除”的方法定位Java服务线上“系统性”故障(转)

一.摘要 由于硬件问题.系统资源紧缺或者程序本身的BUG,Java服务在线上不可避免地会出现一些“系统性”故障,比如:服务性能明显下降.部分(或所 有)接口超时或卡死等.其中部分故障隐藏颇深,对运维和开发造成长期困扰.笔者根据自己的学习和实践,总结出一套行之有效的“逐步排除”的方法,来快速定 位Java服务线上“系统性”故障. 二.导言 Java语言是广泛使用的语言,它具有跨平台的特性和易学易用的特点,很多服务端应用都采用Java语言开发.由于软件系统本身以及运行环境的复杂 性,Java的应用不

一个Tomcat高CPU占用问题的定位

案例背景: 前段时间项目发布了一个V2.1.2大的版本以后,IDC机器CPU不时会突然飙升,而且是"根本停不下来"的样子,一上去了就是100%.想来也纳闷 虽然发了版本,但没有太耗CPU的功能,不应该会让CPU一下子从20%左右飙升到100%,而且是间歇性的,想想也应该是项目本身固有的bug,只不过现在访问量大了才暴露出来. 1.通过top命令看看是哪个进程当用了大量的CPU,得到pid 2.top -H -p [pid]找出此进程中CPU占用排在前头的活动线程,把pid都记录下来.

Cpu飚高show-busy-java-threads一件脚本排查与Arthas线上诊断工具排查实战

spring boot 模拟飚高代码 @Servicepublic class TestWhile{    /* 操作内存对象 */    ConcurrentHashMap map = new ConcurrentHashMap();    private void whileTrue(String threadName) {        // 不设置退出条件,死循环        while (true) {            // 在死循环中不断的对map执行put操作,导致内存gc

[转]线上GC故障解决过程记录

排查了三四个小时,终于解决了这个GC问题,记录解决过程于此,希望对大家有所帮助.本文假定读者已具备基本的GC常识和JVM调优知识,关于JVM调优工具使用可以查看我在同一分类下的另一篇文章: http://my.oschina.net/feichexia/blog/196575 背景说明 发生问题的系统部署在Unix上,发生问题前已经跑了两周多了. 其中我用到了Hadoop源码中的CountingBloomFilter,并将其修改成了线程安全的实现(详情见:AdjustedCountingBloo