线上机器cpu负载200%告警排查

本文介绍了在Java应用中遇到CPU过高告警时的排查方法,包括检查耗时进程、使用jstack查看线程快照、分析GC情况、识别内存泄漏。通过实例和工具如top、jstat、jmap等进行详细步骤说明。

CPU告警排查思路,正常情况就是如下两种情况

  • 执行任务的java线程本身存在bug,死循环或者操作本身耗cpu,导致cpu占用过高
  • jvm发生频繁gc,导致cpu过高

查看耗时较高的进程

  • top命令,并按大写P以cpu利用率排序,确定cpu占用最高的进程为 java进程

  • top -H -p [进程id],注意:此时的PID为线程ID,如下图所示

  • 计算java线程id的16进制值,用jstack看到的线程快照中,线程ID需要转换成小写十六进制值
  1. 可以借助在线转换工具:十进制转换 - 在线进制转换器
  2. linux系统也可以使用如下命令转换  printf "%x\n" [线程ID] 
printf "%x\n" 22304

使用Jstack查看线程快照

#grep的 -B n 前n行
#grep的 -C n 前后各n行
#grep的 -A n 后n行
jstack [进程ID] |grep [转换后的线程ID] -A 30

分析上图发现,查看完整堆栈定位代码位置,该线程进本都在执行

com.xxx.hub.util.CaseNodeParseUtil.addNodeToChildrenIfParentIdEqual(CaseNodeParseUtil.java:1363)

后续进一步分析,需要结合业务代码查看该部分是否存在耗时

查看GC情况

  • 首先使用top查看当前内存的使用情况

  • 查看gc次数,使用命令 jstat -gc [Java进程ID]:

结合上图可知YGC次数1232,FGC共468次

如果GC次数很多的情况,基本可以说明存在频繁GC导致cpu占用高的问题

GC参数说明

S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间 

 使用命令dump 内存堆的存储快照,命令如下

jmap -dump:format=b,file=/tmp/mem.hprof [进程ID]

使用内存分析工具,如Eclipse Memory Analyzer等分析mem.hprof文件,分析内存哪部分占用大,存在内存泄露,导致空间无法释放。 

<think> 我们正在处理关于线上环境CPU飙高排查方法的问题。根据引用内容,已经有一些排查方法的提示,如使用top、jstack、Arthas等工具。我们需要系统地总结这些方法,并补充其他可能的排查步骤。 主要排查步骤: 1. 定位高CPU进程:使用top命令,按CPU排序,找到占用CPU最高的进程ID(PID)。 2. 定位高CPU线程:在top中按`H`(或者使用`top -Hp <pid>`)查看该进程下的线程,记录占用高的线程ID(TID)。 3. 线程ID转换:将TID转换为16进制(因为jstack输出的线程信息是16进制)。 4. 使用jstack获取线程堆栈:`jstack -l <pid> > thread_dump.txt`,然后在堆栈文件中查找对应16进制TID的线程,查看其堆栈信息。 5. 使用Arthas工具:如果环境允许,可以使用Arthas工具,其提供了更便捷的命令,如`dashboard`可以查看整体情况,`thread`命令可以查看线CPU使用情况,`thread -n 3`展示最忙的3个线程,`thread <tid>`查看指定线程的堆栈。 另外,引用[3]提到了使用StopWatch来记录每一步的耗时,这可以在代码级别定位耗时操作,但通常是在开发阶段使用,线上环境可能需要通过日志或者监控来定位。 我们还需要考虑其他可能导致CPU飙高的原因以及排查工具: - 频繁Full GC:使用`jstat -gcutil <pid> <interval> <count>`来查看GC情况,如果发现Full GC次数多且频繁,可能是内存问题导致GC线程占用CPU高。 - 死循环或无限递归:通过线程堆栈查看是否在某个方法中循环。 - 锁竞争激烈:查看线程堆栈中是否有大量线程处于BLOCKED状态。 - 其他系统问题:如系统负载高,使用`vmstat`、`sar`等命令查看系统整体情况。 因此,我们可以将步骤总结为: 一、系统层面定位 1. 使用`top`命令找到高CPU进程。 2. 使用`top -Hp <pid>`或`ps -T -p <pid> -o tid,pcpu,time`找到高CPU线程。 3. 将线程ID转为16进制(`printf "%x" <tid>`)。 二、JVM层面分析 4. 使用`jstack`获取线程堆栈,并查找对应线程的堆栈信息,分析代码。 5. 或者使用Arthas工具(如果已安装): - 启动Arthas:`java -jar arthas-boot.jar` - 使用`dashboard`查看整体情况 - 使用`thread`命令查看线CPU使用情况 - 使用`thread <tid>`查看具体线程堆栈 三、其他可能原因排查 6. 检查GC活动:`jstat -gcutil <pid> 1000 5`(每1秒一次,共5次) 7. 检查内存使用:`jmap -heap <pid>`或`jcmd <pid> GC.heap_info` 四、代码层面分析 8. 结合堆栈信息分析代码,看是否有死循环、频繁执行的方法等。 9. 如果有条件,可以查看应用日志中是否有相关错误或警告。 五、持续监控 10. 使用监控工具(如Prometheus+Grafana)设置告警,提前发现问题。 注意:在生成线程堆栈时,为了确保堆栈的准确性,建议多次dump堆栈,然后对比分析。 下面我们按照要求生成回答,包括相关问题。 </think> ### 线上环境CPU飙高排查方法详解 #### 一、快速定位问题进程/线程 ```mermaid graph TD A[top命令] --> B[定位高CPU进程] B --> C[top -Hp <pid>] C --> D[记录线程ID] D --> E[printf '%x' <tid>] E --> F[转换为16进制线程ID] ``` 1. **系统级定位** - `top` 命令查看系统负载: ```bash top -c # 按P按CPU排序,记录PID ``` - 定位问题线程: ```bash top -Hp <PID> # 查看指定进程的线CPU占用 ps -T -p <PID> -o tid,pcpu,time # 线程级CPU监控 ``` 2. **线程ID转换** 将十进制线程ID转为16进制(jstack分析必需): ```bash printf "%x" <线程ID> # 得到16进制tid ``` #### 二、JVM层分析工具 1. **jstack 线分析** ```bash jstack -l <PID> > thread_dump.txt # 获取线程快照 ``` 在thread_dump.txt中搜索转换后的16进制tid,查看线程堆栈 2. **Arthas 实时诊断**[^2] ```bash # 启动Arthas java -jar arthas-boot.jar dashboard # 实时监控面板 thread -n 3 # 显示最忙的3个线程 thread <16进制TID> # 查看指定线程堆栈 profiler start # 启动CPU性能分析 ``` 3. **JProfiler/VisualVM** 远程连接生产环境(需开启JMX): ```bash -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.ssl=false ``` #### 三、代码层问题定位 1. **常见问题模式** | 线程状态 | 可能原因 | 解决方案 | |----------------|-------------------------|------------------------| | `RUNNABLE` | 死循环/大计算量 | 算法优化 | | `BLOCKED` | 锁竞争 | 减少同步范围 | | `WAITING` | 资源等待 | 超时机制 | 2. **StopWatch 耗时分析**[^3] ```java StopWatch stopWatch = new StopWatch(); stopWatch.start("criticalSection"); // 关键业务代码 stopWatch.stop(); log.info("耗时分析: {}", stopWatch.prettyPrint()); ``` #### 四、典型场景解决方案 1. **死循环问题** - 检查递归调用终止条件 - 避免在循环中执行重型操作(如JSON解析) - 使用`Thread.sleep`释放CPU 2. **锁竞争优化** ```java // 优化前 synchronized(this) { /* 大段代码 */ } // 优化后 private final Object lock = new Object(); synchronized(lock) { /* 最小同步范围 */ } ``` 3. **GC导致CPU飙高** ```bash jstat -gcutil <PID> 1000 5 # 监控GC活动 ``` - 特征:`gc`线CPU占用高 - 解决:调整`-Xmx/-Xms`,优化GC策略 #### 五、预防与监控 1. **持续监控方案** - Prometheus + Grafana:设置CPU阈值告警 - Spring Boot Actuator:`/actuator/metrics/system.cpu.usage` 2. **压测验证** ```bash # 模拟高并发 wrk -t12 -c400 -d30s http://localhost:8080/api ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漁陽

彼此共勉,砥砺前行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值