CPU使用率100%的异常排查

2023/1/1

点击勘误issues (opens new window),哪吒感谢大家的阅读

# CPU使用率100%的异常排查

在生产环境中,CPU使用率飙升至100%是一种常见的性能问题,可能导致系统响应缓慢甚至服务不可用。本文将详细介绍如何排查和解决CPU使用率100%的问题。

# 1. 问题表现

当CPU使用率达到100%时,系统通常会出现以下症状:

  • 系统响应缓慢或无响应
  • 应用程序执行速度变慢
  • 请求处理时间增加
  • 任务队列积压
  • 服务超时或拒绝连接

# 2. 排查工具

# 2.1 Linux系统工具

top命令:实时显示系统中各个进程的资源占用情况

top

使用top命令后,可以按以下键进行排序:

  • P 键:按CPU使用率排序(默认)
  • M 键:按内存使用率排序
  • T 键:按运行时间排序

htop命令:top的增强版,提供更友好的界面和更多功能

htop

ps命令:查看进程状态

# 查看CPU占用最高的前10个进程
ps aux | sort -k3nr | head -10

mpstat命令:查看多处理器统计信息

mpstat -P ALL 2 5  # 每2秒采样一次,共采样5次,显示所有CPU核心的统计信息

pidstat命令:监控进程的CPU使用情况

pidstat -u 2 5  # 每2秒采样一次,共采样5次
pidstat -p <PID> -u 2 5  # 监控特定进程

# 2.2 Java应用工具

jstack:生成Java线程转储

jstack <PID> > thread_dump.log

jstat:监控JVM的GC情况

jstat -gcutil <PID> 1000 10  # 每1秒采样一次,共采样10次

jmap:生成堆转储

jmap -dump:format=b,file=heap_dump.bin <PID>

Arthas:阿里开源的Java诊断工具

# 安装Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

# 使用thread命令查看线程情况
thread -n 3  # 显示CPU使用率最高的3个线程

# 3. 排查步骤

# 3.1 确认CPU使用率

首先使用top命令确认系统整体CPU使用率:

top

关注以下几个指标:

  • %us:用户空间占用CPU百分比
  • %sy:内核空间占用CPU百分比
  • %ni:用户进程空间内改变过优先级的进程占用CPU百分比
  • %id:空闲CPU百分比
  • %wa:等待输入输出的CPU时间百分比

# 3.2 定位高CPU进程

在top命令中,按P键按CPU使用率排序,找出CPU使用率最高的进程,记录其PID。

# 或者使用ps命令
ps aux | sort -k3nr | head -10

# 3.3 分析进程内的线程

找到高CPU进程后,进一步分析该进程内的线程情况:

# 查看进程内的线程CPU使用情况
top -Hp <PID>

记录CPU使用率高的线程ID,将线程ID转换为十六进制:

printf "%x\n" <线程ID>

# 3.4 生成线程转储

对于Java应用,使用jstack生成线程转储:

jstack <PID> > thread_dump.log

在thread_dump.log文件中搜索之前转换的十六进制线程ID,找到对应的线程栈信息。

grep -A 30 "0x<十六进制线程ID>" thread_dump.log

# 3.5 分析GC情况

如果怀疑是GC问题导致的高CPU,使用jstat查看GC情况:

jstat -gcutil <PID> 1000 10

关注以下指标:

  • S0S1EOM:各内存区域使用百分比
  • YGCYGCT:年轻代GC次数和时间
  • FGCFGCT:老年代GC次数和时间
  • GCT:总GC时间

如果频繁发生Full GC,可能是内存泄漏或内存配置不合理。

# 4. 常见原因及解决方案

# 4.1 代码问题

死循环或无限递归

  • 症状:线程栈显示同一方法反复出现
  • 解决方案:修复代码中的逻辑错误,添加适当的退出条件

算法效率低下

  • 症状:CPU密集型计算占用大量资源
  • 解决方案:优化算法,使用更高效的数据结构,考虑增加缓存

资源竞争

  • 症状:多个线程争用同一把锁,导致上下文切换频繁
  • 解决方案:减少锁粒度,使用并发容器,避免长时间持有锁

# 4.2 JVM问题

频繁GC

  • 症状:jstat显示GC活动频繁,GC线程占用大量CPU
  • 解决方案:调整JVM内存参数,增加堆内存,优化对象创建

JIT编译

  • 症状:启动初期CPU使用率高,CompilerThread占用资源
  • 解决方案:预热应用,使用AOT编译,调整JIT编译参数

# 4.3 系统问题

进程数过多

  • 症状:系统进程数量异常增多
  • 解决方案:检查是否有异常进程创建,限制进程数量

系统中断处理

  • 症状:系统CPU使用率高,但用户进程CPU使用率不高
  • 解决方案:检查硬件问题,更新驱动,调整系统参数

# 5. 实战案例

# 案例一:Java应用CPU飙升

现象:生产环境中一个Java应用CPU使用率突然飙升至100%,系统响应缓慢。

排查过程

  1. 使用top命令确认Java进程CPU使用率接近100%
  2. 使用top -Hp命令找到占用CPU最高的线程ID
  3. 将线程ID转换为十六进制:printf "%x\n" 12345
  4. 使用jstack生成线程转储并分析
  5. 发现问题线程在执行一个无限循环的操作

解决方案:修复代码中的无限循环问题,添加适当的退出条件和超时机制。

# 案例二:频繁GC导致CPU高负载

现象:应用运行一段时间后CPU使用率逐渐升高,响应变慢。

排查过程

  1. 使用jstat发现Full GC频繁发生
  2. 使用jmap生成堆转储并分析
  3. 发现某个集合对象不断增长,没有释放

解决方案:修复内存泄漏问题,确保临时对象能够被及时回收。

# 6. 预防措施

# 6.1 监控告警

  • 设置CPU使用率阈值告警,如连续5分钟超过80%触发告警
  • 监控GC频率和时间,设置合理的告警阈值
  • 监控线程数量,防止线程爆炸

# 6.2 性能测试

  • 在上线前进行充分的性能测试和压力测试
  • 模拟高并发场景,验证系统在极限情况下的表现
  • 进行长时间的稳定性测试,发现潜在的资源泄漏问题

# 6.3 代码审查

  • 重点关注循环、递归等可能导致CPU密集的代码
  • 检查资源释放是否完整
  • 避免使用低效算法处理大量数据

# 7. 总结

CPU使用率100%的问题排查是一个系统性工作,需要从操作系统、应用程序、JVM等多个层面进行分析。掌握相关工具和方法,可以帮助我们快速定位和解决问题,保障系统的稳定运行。

在实际工作中,建议建立标准的问题排查流程和工具集,提前做好监控和告警,做到早发现、早处理,避免问题扩大化。同时,持续优化代码质量和系统架构,从根本上减少高CPU问题的发生。

上次更新: 2025/6/14 02:02:58