CPU 100% 故障排查实战:从告警到根因的全链路分析与 10 大场景
来源:马哥Linux运维 | 发布日期:2026-06-03
CPU 使用率组成
| 类别 | 含义 | 说明 |
|---|---|---|
| us | 用户态 CPU | 应用自身计算逻辑 |
| sy | 内核态 CPU | 系统调用、内存分配、I/O |
| wa | 等待 I/O | 磁盘/网络 I/O 瓶颈 |
| hi/si | 硬/软中断 | 网卡收包、存储中断风暴 |
| id | 空闲 | 100% 表示 CPU 完全空闲 |
多核机器上 top 显示 CPU% 按单核计算(8 核满跑 = 800%),判断是否跑满看 id 列是否为 0 以及 load average 是否远大于 CPU 核心数。
排查七步法
第一步:确认影响范围
单台还是集群?影响多少业务?什么时候开始的?
# K8s 集群
kubectl top nodes
kubectl get pods -o wide | grep -v Running
第二步:定位异常进程
top # Shift+P 按 CPU 排序
top -bn1 -p <PID> # 单进程 CPU
# 可疑进程查启动路径和网络连接
ls -la /proc/<PID>/exec
ss -tunapl | grep <PID>
第三步:分析 CPU 来源
pidstat -p <PID> 1 5 # %usr vs %system
# us 高 → 应用计算;sy 高 → 大量系统调用
Java 进程优先看 GC:
jstat -gcutil <PID> 1000 10
# 关注: O(Old使用率) YGC/YGCT FGC/FGCT
# FGC 频繁 + GCT 高 → GC 是 CPU 主因
第四步:线程级定位
# top 线程模式 → hex 转换 → jstack 搜索
top -bn1 -H -p <PID> # 找 CPU 最高的线程 PID
printf '%x\n' <decimalPID> # 转十六进制
jstack <PID> > /tmp/jstack.log
grep -A 20 "nid=0x<hex>" /tmp/jstack.log
# 或直接用 arthas
thread -n 10 # Top 10 CPU 线程
第五步:系统级分析
vmstat 1 5 # r(运行队列)/us/sy/wa
mpstat -P ALL 1 5 # 每核 CPU
iostat -x 1 5 # 磁盘 I/O
perf record -F 99 -p <PID> -g -- sleep 30 && perf report
第六步:定位根因
通过前五步应能判断根因属于哪类。见下方10大场景速查。
第七步:修复及验证
修复根因后验证:
watch -n 2 "top -bn1 | head -20" # CPU 回落
watch -n 5 "jstat -gcutil <PID> \| tail -1" # GC 正常
curl -o /dev/null -s -w "RTT: %{time_total}s\n" http://localhost:8080/health
真实案例:MySQL 备份锁导致的级联故障
故障链路
MySQL 从库备份锁表 → 从库查询超时 → 线程池 200 个请求积压
→ Old 区持续上涨 → Full GC 每 30 秒/次(STW 5-8 秒)→ CPU 100%
排查过程
top看到 Java 进程 CPU 900%+(16核)jstat -gcutil→ Old 区 99%,FGC 每 30 秒一次- arthas 看线程 → 180 个线程处于 TIMED_WAITING(等数据库返回)
- 联系 DBA → 从库备份锁表导致复制延迟
修复
- 临时(10 分钟): 关闭备份任务释放表锁,CPU 立即回落
- 根本(3 天): 备份加
--single-transaction;JVM-Xmx从 4g 提到 8g;添加从库延迟告警;超时熔断降级到主库
10 大 CPU 故障场景速查
| 场景 | 特征 | 排查工具 | 修复方向 |
|---|---|---|---|
| GC 频繁 | O 区持续上涨,FGC 次数多 | jstat -gcutil |
增大 -Xmx、调 GC 算法、修复内存泄漏 |
| 死循环/无限递归 | 单线程 CPU 固定占满 | top -H → jstack 找栈 |
修复代码逻辑 |
| 多线程锁竞争 | 大量线程 Blocked | jstack 搜 waiting for monitor |
减小锁粒度、用并发容器 |
| 正则回溯 | 偶发 CPU 飙高 | 火焰图发现 Pattern 相关栈 | 避免嵌套量词、用原子组 |
| 频繁序列化 | 每次请求 new ObjectMapper | 火焰图看 JSON 序列化热点 | 复用 ObjectMapper |
| JNI 调用 | Java 进程 us 高但无 Java 栈 | jstack 搜 JNI/native |
检查 native 库代码 |
| 网络 I/O 中断风暴 | si(软中断)高 | cat /proc/softirqs |
多队列网卡、RPS 调优 |
| 加密解密 | HTTPS/AES 密集型 | perf stat -e 'crypto' |
用 AES-NI 硬件加速、TLS 1.3 |
| Python GIL | Python 多线程 CPU 利用率低 | ps -eLf \| grep <PID> |
用多进程替代多线程 |
| 数据库慢查询 | wa 高,大量数据库线程阻塞 | SHOW FULL PROCESSLIST |
优化查询、加索引、读写分离 |
其他语言进程排障
Python
pidstat -t -p <PID> 1 5
py-spy record -o /tmp/profile.svg --pid <PID>
Go
curl http://localhost:6060/debug/pprof/profile?seconds=30 > cpu.prof
go tool pprof cpu.prof # 交互界面输入 top
JVM 配置参考(8 核 16G 机器)
java -Xms8g -Xmx8g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/heapdump.hprof \
-Xlog:gc*:file=/var/log/gc.log:time,uptime,level,tags:filecount=10,filesize=10M \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-jar your-app.jar
故障复盘检查清单
□ 故障发生/发现/恢复时间
□ 影响范围(哪些业务/用户)
□ 根因 + 触发条件 + 扩大因素
□ 临时修复 + 根本修复措施
□ 监控盲区(需补充的监控)
□ 流程改进 + 预防措施
风险提醒
| 操作 | 风险 | 建议 |
|---|---|---|
| 重启 Java 进程 | 丢失 JVM 状态(线程栈/GC/内存分布) | 先分析再重启,保留现场 |
strace -f |
进程变慢 10x+ | 用 -c 统计模式替代逐行跟踪 |
jmap -dump |
触发 Full GC,消耗大量磁盘 I/O | 低峰期操作,导出到独立磁盘 |
perf record |
对性能影响较小 | 采样时间不宜过长 |
部署回滚
kubectl rollout history deployment/<name> -n <ns>
kubectl rollout undo deployment/<name> -n <ns>
kubectl rollout undo deployment/<name> -n <ns> --to-revision=<N>
关联页面
| 页面 | 关联点 |
|---|---|
| cpu-spike-troubleshooting-guide | CPU 排查方法论 |
| java-cpu-100-case-study | Java CPU 100% 排查实战 |
| cpu-spike-3-commands | 三命令排查法 |
| fullstack-performance-troubleshooting | 全栈性能排障 |
| server-performance-four-dimensions | 服务器五维排查 |
| jvm-container-oom-offheap-troubleshooting | JVM OOM 排障 |