背景
一大早收到运维同学反馈、线上某台机器cpu的负载达到了97%以上,为了不影响机器上服务的正常运行,急需找到导致负载过高的原因并将负载降到合理的区间。
用到命令
top/uptime:查看负载情况
语法
top [-] [d delay] [q] [c] [S] [s] [i] [n] [b]参数说明:
- d : 改变显示的更新速度,或是在交谈式指令列( interactive command)按 s
- q : 没有任何延迟的显示速度,如果使用者是有 superuser 的权限,则 top 将会以最高的优先序执行
- c : 切换显示模式,共有两种模式,一是只显示执行档的名称,另一种是显示完整的路径与名称
- S : 累积模式,会将己完成或消失的子进程 ( dead child process ) 的 CPU time 累积起来
- s : 安全模式,将交谈式指令取消, 避免潜在的危机
- i : 不显示任何闲置 (idle) 或无用 (zombie) 的进程
- n : 更新的次数,完成后将会退出 top
- b : 批次档模式,搭配 "n" 参数一起使用,可以用来将 top 的结果输出到档案内
jps:查看java进程
jstack:Java进程中线程的堆栈信息跟踪工具
通过男人手册man查看jstack命令介绍
$jstack [ option ] pid
参数说明:
pid: java应用程序的进程号,一般可以通过jps来获得;
-F:Force a stack dump when jstack [-l] pid does not respond.
-l:Long listing. Prints additional information about locks such as a list of owned java.util.concurrent ownable synchronizers.
jstat:堆内存各部分的使用量,以及加载类的数量
Jstat是JDK自带的一个轻量级小工具。全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控
语法:jstat [ generalOption, outputOptions vmid, [ interva,count ]
参数:
- generalOption: 一般使用-gcutil查看GC情况
- vmid: 虚拟机进程号,即当前运行的java进程号
- interval: 间隔时间,单位为秒或毫秒
- count: 打印次数,如果缺省则打印无数次
查询GC总体使用情况:jstat -gcutil 23484 1000 5
垃圾总体回收统计:jstat -gc 18528 1000 5
新生代垃圾回收统计:jstat -gcnew 18528 1000 5
堆内存统计
jstat -gccapacity 18528 1000 5 //整体统计jstat -gcnewcapacity 18528 1000 5 //新生代统计
jstat -gcoldcapacity 18528 1000 5 //老年代统计
ps:查看进程信息
排查思路
第一步:使用top命令查看负载的情况,查到负载过高的进程号
执行top -c ,显示进程运行信息列表
键入P (大写p),进程按照CPU使用率排序
根据top命令查看负载情况、cpu占用情况、确定进程号pid
load average后面的三个数分别是1分钟、5分钟、15分钟的负载情况。(我的机器4核16g修复前都超过了10)
load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了
提示:也可以使用uptime命令查看当前负载情况、链接用户数等信息
13:29:09 up 2 days, 7:13, 4 users, load average: 0.07, 0.02, 0.00
In this line:
- 13:29:09 is the current time
- 2 days, 7:13 is the uptime
- 4 users shows how many users currently use your system
- 0.07 – average load for the last minute
- 0.02 – average load for the last 5 minutes
- 0.00 – average load for the last 15 minutes
第二步:根据pid,通过ps命令确定是哪个服务出现了异常
ps -ef|grep pid
确定了服务之后、可以找下服务对应负责人,看看服务是不是有什么异常
第三步:top输出中打开线程查看,使用命令 top -H
top -Hp pid ,显示一个进程的线程运行信息列表
键入P (大写p),线程按照CPU使用率排序
提示:可以通过键盘上的c键,切换输出模式,方便查看更详细的信息
第四步:查看堆栈信息
找到对应的线程号之后,使用jstack pid > jstack.txt 命令,将进程的堆栈存入txt文档内,将通过top -H查到的线程pid转换成16进制(可以借助在线转换工具,之所以要转化为16进制,是因为堆栈里,线程id是用16进制表示的。)或者 使用 printf "%x\n" pid,然后在jstack.txt文档内查到对应的数据,这样就可以看到对应的信息堆栈信息了
看的出来:"VM Thread"就是该cpu消耗较高的线程,查看相关文档我们得知,VM Thread是JVM层面的一个线程,主要工作是对其他线程的创建,分配和对象的清理等工作的。从后面几个线程也可以看出,JVM正在进行大量的GC工作。这里的原因已经比较明显了,即大量的GC工作导致项目运行缓慢
第五步:那么具体是什么原因导致这么多的GC工作呢?进一步查看gc情况
jstat -gcutil 64015 1000 5
第六步:定位原因的现有jvm的参数无法满足gc的正常使用,最终调高jvm的xmx/xms/xmn的启动参数,问题得以解决