JAVA环境的CPU高负载问题排查小计

JAVA环境的CPU高负载问题排查小计

赵阳 360云计算
JAVA环境的CPU高负载问题排查小计

女主宣言

目前互联网公司的web环境大部分还是以LNMP为主,php更多时候还是做为web服务端开发的首选。做为运维工程师排查php方面的问题相信大家都是信手拈来,但是在面对JAVA这种“高冷”的环境时,相信还是有很多同学会显得束手无策。今天就为大家分享一篇简单的JAVA环境trouble shooting的小技巧。
PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!

背景简介

目前互联网公司的web开发基本都是使用PHP,在web领域PHP还是拥有得天独厚的优势,简单易用、并且拥有众多粉丝的它已经占据了web领域的半壁*。而JAVA更多时候还是做为电信、金融等领域的首选。

然而做为运维人员,也因行业的不同,专注的技术领域也有所不同,毕竟大多数同学还是在“php当家的”互联网公司就职,在排查JAVA环境的问题时,很多同学都是经验不足,从而显得有些“懵B”。相信在看完这篇文章之后,大家都能永远的告别“懵B的自己”。

1

场景

某个业务的WEB服务端是JAVA环境的,一天收到了大量的CPU_idle报警,登录服务器排查发现是JAVA进程占用CPU较高所致,而且该问题属于断断续续这种。

具体情况如下图:
JAVA环境的CPU高负载问题排查小计
可以看到该主机的CPU使用率已经接近满负荷。

2

问题分析

根据问题定位:CPU占用过高是JAVA进程,属于tomcat服务,tomcat一般出现问题都是full GC之类的内存问题,占用CPU过高大致可以定位是代码层出现问题,导致占用CPU过高。

3

使用jstack定位问题

jstack介绍:


jstack是一个堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息。

用法:
jstack [ option ] <pid>                                                      //指定进程号(pid)的进程#指定核心文件
jstack [ option ] <executable <core>                                //指定核心文件
jstack [ option ] [server-id@]<remote-hostname-or-IP>   //指定远程调试服务器

常用参数:
pid: java应用程序的进程号,一般可以通过jps来获得;
executable:产生core dump的java可执行程序;
core:打印出的core文件;
remote-hostname-or-ip:远程debug服务器的名称或IP;
server-id: 唯一id,假如一台主机上多个远程debug服务; 

基本参数: 
-l     //长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表
-F    //当’jstack [-l] pid’没有相应的时候强制打印栈信息
-m    //打印java和native c/c++框架的所有栈信息
pid   //需要被打印配置信息的java进程id,可以用jps查询

方法

用命令查看比较占用CPU非常高的线程的id,图中主进程id是10832,问题线程id是11358。

JAVA环境的CPU高负载问题排查小计


细节:
1.也可以使用ps -mp $PID -o THREAD,tid,time | sort -k 2 -r | head -20来查看线程运行情况。

2.jstack内部的进程号是16进制的,所以要将线程id转换成16进制
    $ echo "obase=16;11358" | bc
    $ 2C5E

jstack抓取日志,jstack -l 10832,经过判断为正则表达式匹配导致CPU过高。
如图:
JAVA环境的CPU高负载问题排查小计

扩展

Jstat

这是一个比较实用的一个命令,可以观察到classloader,compiler,gc相关信息。可以时时监控资源和性能。

命令格式


-class                    //统计class loader行为信息
-compile                //统计编译行为信息
-gc                         //统计jdk gc时heap信息
-gccapacity            //统计不同的generations(不知道怎么翻译好,包括新生区,老年区,permanent区)相应的heap容量情况
-gccause                //统计gc的情况,(同-gcutil)和引起gc的事件
-gcnew                   //统计gc时,新生代的情况
-gcnewcapacity      //统计gc时,新生代heap容量
-gcold                      //统计gc时,老年区的情况
-gcoldcapacity        //统计gc时,老年区heap容量
-gcpermcapacity     //统计gc时,permanent区heap容量
-gcutil                      //统计gc时,heap情况

Jmap
得到运行java程序的内存分配的详细情况。例如实例个数,大小等。

命名行格式
jmap [ option ] pid
jmap [ option ] executable core
jmap [ option ] [server-id@]remote-hostname-or-IP

-dump:[live,]format=b,file=<filename>     //使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-finalizerinfo              //打印正等候回收的对象的信息.
-heap                        //打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.
-histo[:live]                //打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
-permstat                 //打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来.
-F                             //强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.
-h | -help                  //打印辅助信息
-J                             //传递参数给jmap启动的jvm.
上一篇:linux使用jstack来找出死循环的java代码


下一篇:日常Bug排查-系统失去响应-Redis使用不当