在后端面试中,面试题:如何排查线上 CPU 100% 飙高直接考察候选人的线上问题处理能力。一个优秀的排查方案需要体现"系统化思维、工具熟练度、问题预判力"三大核心素养,这正是鳄鱼java在生产环境中处理过200+CPU故障总结的实战经验。本文将通过"现象确认-进程定位-线程分析-代码溯源-解决方案"五步法,详解12个关键操作步骤,助你在面试中展现运维与开发的复合能力。
一、故障现象确认:从监控告警到现场诊断

处理CPU飙高问题的第一步是确认故障范围。鳄鱼java建议按以下流程操作:
1. 监控指标验证
- 查看监控系统(Prometheus/Grafana)CPU使用率曲线,确认是否持续>80%
- 检查负载均值(load average),若1分钟负载>CPU核心数,说明存在进程争抢资源
- 观察IO指标(iostat),排除IO等待导致的CPU等待(%iowait高时可能是IO问题)
2. 登录服务器验证
使用top命令实时观察CPU使用情况:
top - 14:30:00 up 120 days, 2:15, 2 users, load average: 8.50, 7.20, 6.80 Tasks: 289 total, 3 running, 286 sleeping, 0 stopped, 0 zombie %Cpu(s): 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 32786820 total, 18345620 free, 8965432 used, 5475768 buff/cache KiB Swap: 0 total, 0 free, 0 used. 23258940 avail Mem关键指标说明:PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12345 appuser 20 0 38.5g 8.2g 1.2g R 198.7 25.6 45:32.15 java -jar app.jar
- %CPU:进程CPU使用率(超过100%说明多线程)
- S列:R(运行中)状态的进程才会占用CPU
- TIME+:累计CPU占用时间,可判断是否长期高负载
鳄鱼java提示:若多个进程CPU总和接近100%,可能是整体负载过高;单个进程CPU>100%,通常是多线程问题。
二、进程定位:从系统到Java进程的聚焦
确认高CPU进程是排查的关键一步。鳄鱼java总结两种场景的处理方式:
1. Java进程CPU飙高
通过top命令找到CPU最高的Java进程PID(如12345),记录进程ID后执行:
# 查看进程启动参数(确认是否为目标应用) ps -ef | grep 12345输出示例:查看进程打开的文件和网络连接(排查是否有异常IO)
lsof -p 12345
查看进程线程情况(-H显示线程,-p指定进程)
top -Hp 12345
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12356 appuser 20 0 38.5g 8.2g 1.2g R 99.3 25.6 22:15.32 java 12357 appuser 20 0 38.5g 8.2g 1.2g R 98.9 25.6 22:10.87 java可见线程12356和12357占用CPU最高,需进一步分析这两个线程。
2. 非Java进程CPU飙高
- 若为数据库进程(mysqld/postgres):检查慢查询、连接数、索引使用情况
- 若为Nginx:查看access.log是否有异常请求(如大量静态资源请求)
- 若为未知进程:使用file /proc/{pid}/exe查看可执行文件路径,判断是否为恶意程序
鳄鱼java技术团队曾遇到过因crontab定时任务执行死循环脚本导致CPU飙高的案例,通过上述方法快速定位并解决。
三、线程分析:从线程ID到Java堆栈
针对Java进程,下一步需要将系统线程ID转换为Java线程并获取堆栈。鳄鱼java推荐两种工具方案:
1. 传统命令行方案
- 转换线程ID为十六进制:系统线程ID是十进制,jstack输出的是十六进制(如12356 → 0x3024)
printf "%x\n" 12356 # 输出3024- 获取Java堆栈:
jstack 12345 > jstack.log grep -A 20 3024 jstack.log # 查找线程堆栈堆栈示例:
"pool-1-thread-1" #12 prio=5 os_prio=0 tid=0x00007f8718009800 nid=0x3024 runnable [0x00007f871fe41000]
java.lang.Thread.State: RUNNABLE
at com.crocodilejava.service.DataProcessor.calculate(DataProcessor.java:45)
at com.crocodilejava.service.DataProcessor.process(DataProcessor.java:23)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
可见线程在DataProcessor.java:45行执行calculate方法时出现问题。
2. Arthas工具方案(推荐)
阿里开源的Arthas工具可简化线程分析:
# 启动Arthas并 attach 到目标进程 java -jar arthas-boot.jar 12345Arthas的优势在于:查看线程CPU使用情况
thread -n 3 # 显示CPU最高的3个线程
查看指定线程堆栈
thread 12356 # 直接使用十进制线程ID
- 无需手动转换十六进制
- 支持实时线程状态监控
- 可查看方法执行耗时(thread -t)
鳄鱼java技术团队在处理生产故障时,使用Arthas将线程定位时间从15分钟缩短至3分钟。
四、代码溯源:从堆栈信息到问题根因
获取线程堆栈后,需要结合代码分析CPU飙高的根本原因。鳄鱼java总结五大常见场景及解决方案:
1. 死循环/无限递归
- 特征:线程状态为RUNNABLE,堆栈中方法调用固定且重复
- 案例:
// 错误代码:循环条件永远为true
while (true) {
if (list.size() > 0) {
process(list.remove(0));
}
// 缺少else分支,当list为空时进入空循环
}
- 解决:添加循环退出条件,或使用阻塞队列(如LinkedBlockingQueue)替代手动轮询
2. 正则表达式回溯爆炸
-
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。





