遇到cpu突然飙高,要快速止血。
- 若CPU持续100%且严重影响核心业务,及时重启实例,但需先保存现场信息(如堆栈、内存快照)
1. 快速定位高 CPU 进程
目标:确认是哪个进程导致 CPU 使用率过高。
工具:top
、htop
、ps
。
操作:
# 查看实时 CPU 使用情况(按 P 按 CPU 排序)
top -c
# 或使用精简版
ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -n 10
输出示例:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 app 20 0 10.2g 3.2g 1.1g R 98.6 20.3 10:30.1 java
结论:确认目标进程(如 PID=1234
的 Java 进程)。
2. 定位进程内高 CPU 线程
目标:找到进程内消耗 CPU 最高的线程。
工具:top
(线程模式)、ps
。
操作:
# 进入 top 后按 H 切换线程模式,或直接查看线程
top -H -p 1234
# 或使用 ps
ps -T -p 1234 -o tid,pcpu,state,cmd --sort=-pcpu | head -n 5
输出示例:
TID %CPU STATE COMMAND
4567 95.2 R java
结论:记录高 CPU 线程 ID(如 TID=4567
),需转换为 16 进制(0x11D7
)。
3. 获取线程堆栈信息(以 Java 为例)
目标:分析线程正在执行的代码。
工具:jstack
、Arthas
。
操作:
# 生成线程快照
jstack 1234 > thread_dump.txt
# 或使用 Arthas 实时监控
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar 1234 # 附加到目标进程
thread -n 3 # 查看最忙的 3 个线程
分析:
在 thread_dump.txt
中搜索 nid=0x11D7
,找到对应线程的堆栈:
"HighCpuThread" #32 daemon prio=5 os_prio=0 tid=0x00007f8a4410a800 nid=0x11d7 runnable [0x00007f8a2c4f0000]
java.lang.Thread.State: RUNNABLE
at com.example.App.loopMethod(App.java:20) // 死循环代码位置
4. 分析问题根源
常见原因及排查方法:
问题类型 | 排查方法 |
---|---|
死循环/无限递归 | 检查堆栈中频繁执行的代码(如 while(true) 、未退出的递归调用)。 |
频繁 GC | 检查 GC 日志(jstat -gcutil 1234 1000 ),观察是否因 Full GC 导致 CPU 飙升。 |
锁竞争 | 查看线程是否处于 BLOCKED 状态(如 synchronized 或 ReentrantLock 竞争)。 |
外部依赖阻塞 | 检查网络或 IO 操作(如数据库慢查询、HTTP 请求超时)。 |
5. 解决方案与优化
根据原因针对性处理:
- 代码逻辑问题(如死循环)
- 修复代码逻辑,避免无限循环或递归。
- 示例:
// 修复前(无退出条件)
while (true) { processData(); }
// 修复后(添加退出条件)
while (isRunning) { processData(); }
- GC 问题
- 调整 JVM 参数(如增大堆内存、优化垃圾回收器)。
- 示例:
# 使用 G1 垃圾回收器并增加堆内存
java -Xms4g -Xmx4g -XX:+UseG1GC -jar app.jar
- 锁竞争
- 优化锁粒度(如缩小同步代码块)、使用无锁数据结构(如
ConcurrentHashMap
)。 - 示例:
// 缩小锁范围
synchronized (this) { // 原锁整个方法
updateSharedResource();
}
- 优化锁粒度(如缩小同步代码块)、使用无锁数据结构(如
- 外部依赖问题
- 优化慢查询(如添加数据库索引)、设置超时与熔断(如 Hystrix、Resilience4j)。
6. 预防措施
- 监控告警:部署 Prometheus + Grafana 监控 CPU、GC、线程状态。
- 压测与 Profiling:定期使用 JMeter 压测,结合 Async Profiler 生成火焰图分析热点代码。
- 代码审查:避免循环内阻塞操作、确保资源释放(如关闭连接)。
高频问题场景及诊断方法
场景 | 诊断工具/方法 | 典型case |
---|---|---|
线程池爆炸 | jstack 查看线程前缀 + 监控线程池指标(如DynamicTP) | 未配置拒绝策略导致创建数千线程 |
热key问题 | Redis集群代理层监控(如自研proxy) + redis-cli --hotkeys | 突发新闻导致缓存击穿 |
RPC链路异常 | 全链路Trace中筛选高耗时调用 + 下游服务熔断日志 | 下游超时引发上游线程阻塞 |
JIT编译风暴 | -XX:+PrintCompilation 日志 + JFR录制 | 高频部署导致反复编译 |
内核态CPU高 | perf top -k 查看内核调用 + systemtap 分析 | 容器网络插件软中断不均 |
总结流程图
CPU 飙升 → top 定位进程 → 线程分析 → 堆栈快照 → 代码/资源分析 → 修复优化
声明:来自程序员千羽,仅代表创作者观点。链接:https://eyangzhen.com/2092.html