双11大战开始了,这几天公司系统压测,CPU各种报警,于是找了篇关于CPU高问题排查的文章。

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

(友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hankchen

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

根据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命令。可以查看某个进程的当前线程栈运行情况。

 

(友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hankchen

CPU高问题排查的更多相关文章

  1. 再一次生产 CPU 高负载排查实践

    前言 前几日早上打开邮箱收到一封监控报警邮件:某某 ip 服务器 CPU 负载较高,请研发尽快排查解决,发送时间正好是凌晨. 其实早在去年我也处理过类似的问题,并记录下来:<一次生产 CPU 1 ...

  2. Ubuntu1804下k8s-CoreDNS占CPU高问题排查

    1.背景: 最近在ubuntu804上适配k8s的时候,部署到业务pod的时候,出现了服务器卡死,top查看发现负载很高,进行CPU排序发现如下信息,可知是CoreDNS服务导致. 2. 分析排查: ...

  3. CPU高的排查

    之前有朋友反馈说发的内容希望有个梯度,逐步加深,前面发了几篇关于jvm源码分析的文章,可能我觉得我已经把内容写得浅显易懂了,但是对于某些没怎么接触的同学来说还是比较难理解,这个我以后慢慢改进吧,今天发 ...

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

    问题描述:生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析:1,程序属于CPU密集型,和开发沟通过, ...

  5. STORM在线业务实践-集群空闲CPU飙高问题排查

    源:http://daiwa.ninja/index.php/2015/07/18/storm-cpu-overload/ 2015-07-18AUTHORDAIWA STORM在线业务实践-集群空闲 ...

  6. Java服务器内存过高&CPU过高问题排查

    一.内存过高 1.内存过高一般有两种情况:内存溢出和内存泄漏 (1)内存溢出:程序分配的内存超出物理机的内存大小,导致无法继续分配内存,出现OOM报错 (2)内存泄漏:不再使用的对象一直占据着内存不释 ...

  7. linux Java项目CPU内存占用高故障排查

    linux Java项目CPU内存占用高故障排查 top -Hp 进程号 显示进程中每个线程信息,配合jstack定位java线程运行情况 # 线程详情 jstack 线程PID # 查看堆内存中的对 ...

  8. cpu load过高问题排查

    load average的概念 top命令中load average显示的是最近1分钟.5分钟和15分钟的系统平均负载. 系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少 ...

  9. centos7-java模拟cpu占用高及排查

    环境 centos7 1核2GB Java8 模拟cpu占用高 新建一个名为jvm-learn的springboot项目 模拟代码如下 import org.springframework.boot. ...

随机推荐

  1. 文档在线预览开源实现方案三:OpenOffice + PDFRenderer + js

    之前的方案无法很好地解决异构平台及不同浏览器的兼容性问题,如方案一需要客户端浏览器支持flash而移动端浏览器无法支持这点,虽然移动端浏览器支持方案二,但是一些老版本的IE浏览器无法支持,例如IE8就 ...

  2. C++ 部分知识点

    1,return语句返回函数的返回值,就是函数的类型,函数只能有唯一的返回值: return可以停止函数,并将控制返回主调函数: 一个函数可以有许多return语句,执行到哪个return语句,哪个起 ...

  3. android下拉刷新控件 android-pulltorefresh

    运行效果: 介绍:ListView.ViewPager.WevView.ExpandableListView.GridView.(Horizontal)ScrollView.Fragment上下左右拉 ...

  4. jquery 获取当前对象的id取巧验证的一种方法

    <!doctype html><html><head><meta charset="utf-8"><title>titl ...

  5. Python中fileinput模块使用

    fileinput模块可以对一个或多个文件中的内容进行迭代.遍历等操作.该模块的input()函数有点类似文件 readlines()方法,区别在于前者是一个迭代对象,需要用for循环迭代,后者是一次 ...

  6. JavaScript忍者秘籍——闭包

    概要:本篇博客主要介绍了JavaScript的闭包 1.闭包的工作原理 简单地说,闭包就是一个函数在创建时允许该自身函数访问并操作该自身函数之外的变量时所创建的作用域. 例如: var outerVa ...

  7. C#中的DataSet添加DataTable问题

    最近在使用DataTable来给前台控件绑定数据,开始时查了网上的一些给DataSet添加DataTable时需要注意的地方,一般都要添加表名并且使用DataTable.Copy()方法,否则会报错, ...

  8. 设计模式-GoF23

    书呢,是2012年双11买的. 没有面向对象程序经验的人,果然还是看不懂的.

  9. HDU 4291 A Short problem(2012 ACM/ICPC Asia Regional Chengdu Online)

    HDU 4291 A Short problem(2012 ACM/ICPC Asia Regional Chengdu Online) 题目链接http://acm.hdu.edu.cn/showp ...

  10. linux + shell 命令等

    Linux命令[注意:建议用UltraEdit打开] 一.文件处理命令 1.命令格式与目录处理命令 ls –a[查看隐藏文件] ls –l[查看文件信息长格式显示] ls –d[查看指定目录的详细信息 ...