最近朋友老王去某大厂面试,被问到一个经典问题:“线上服务CPU突然飙到100%,你怎么处理?”老王支支吾吾半天,最后憋出一句“重启服务器”,结果当场被挂。事后他跟我吐槽:“这问题明明实际工作中遇到过,但一紧张全忘了!”
其实这类问题就像程序员界的“脑筋急转弯”,看似简单,答不好却能直接暴露你的经验短板。今天我们就来拆解这个高频面试题,手把手教你用“破案思维”搞定CPU爆满问题。(友情提示:文末有压箱底的排查口诀,看完就能用!)
CPU爆满的三大“元凶”
CPU飙到100%就像高速公路突然堵死,背后往往藏着三类“车祸现场”:
代码里的“鬼打墙”
实习生写的死循环、正则表达式匹配卡死、甚至是同事留下的synchronized滥用——这些代码级的坑,就像在代码里埋了定时炸弹。去年某电商大促,就因一段正则表达式匹配代码导致CPU满载,直接损失百万订单量。
线程的“春运现场”
想象一下1000辆汽车(线程)挤在单车道(CPU核心)上:
- 线程池配置不合理,瞬间创建上千线程
- 未做限流的接口被疯狂调用
- 自旋锁导致线程原地“打转”
某社交APP曾因消息推送服务线程池参数配错,导致服务器直接“罢工”8小时。
内存的“垃圾围城”
JVM内存泄漏时,GC线程就像清洁工疯狂打扫却永远清不完垃圾:
- 短生命周期对象海量创建
- 静态集合不当引用导致OOM
- 未关闭的数据库连接池
有家公司监控系统自己吃掉80%CPU,最后发现是日志组件频繁触发Full GC。
5步定位法:像福尔摩斯一样查案
第1步:锁定“案发现场”
top -c # 按P排序,找到CPU占用最高的Java进程PID
比如发现PID为9527的进程吃掉了98%的CPU,这就是我们的“头号嫌犯”。
第2步:揪出“闹事线程”
top -Hp 9527 # 查看该进程下所有线程
printf "%x\n" 12345 # 把高CPU线程ID转为16进制(假设得到3039)
现在我们知道线程0x3039在疯狂搞事情。
第3步:获取“犯罪证据”
jstack 9527 > dump.log # 导出线程快照
用VSCode打开日志,搜索nid=0x3039,你可能会看到这样的线索:
"Thread-0" #1 prio=5 os_prio=0 tid=0x00007f4874009800
java.lang.Thread.State: RUNNABLE
at com.example.BugService.doSomething(BugService.java:17)
第4步:现场还原术
- 第17行代码是while(true){...}?
- 还是正则表达式Pattern.compile("(a+)+") ?
- 或者是未加锁的HashMap并发操作?
第5步:终极武器Arthas
如果jstack不够直观,可以用阿里开源的Arthas神器:
thread -n 3 # 显示最忙的3个线程
thread 12345 # 查看指定线程调用栈
dashboard # 实时监控面板
去年我帮朋友排查问题时,用Arthas直接定位到是MyBatis动态SQL解析异常,整个过程不到3分钟。
止血与预防:从救火到防火
紧急止血方案
场景 | 应急措施 | 后续优化 |
死循环 | 动态修改循环条件 | 增加超时熔断机制 |
线程爆炸 | 调整线程池参数 | 接入Sentinel限流 |
内存泄漏 | 重启服务 | 接入Arthas在线诊断 |
长效防御体系
- 监控三件套:Prometheus监控CPU使用率、JVM内存、线程数(阈值建议设70%)
- 压测必杀技:用JMeter模拟秒杀场景,提前暴露线程安全问题
- 代码军规:禁止在循环内创建对象正则表达式必须预编译线程池参数通过Apollo动态配置
- 逃生通道设计:关键服务添加CPU过载保护,自动触发熔断降级
真实案例:一段正则引发的血案
某天气查询接口凌晨突发CPU告警,值班同学用jstack发现大量线程卡在java.util.regex.Pattern 。原来新来的同事写了段“看似无害”的代码:
// 错误示范
String input = "aaaaaaaaaaaaaab";
boolean isMatch = input.matches("(a+)+b");
这其实是著名的“正则灾难”模式!当输入恶意字符串时,匹配时间复杂度呈指数级增长。改用预编译正则+超时检测后,CPU立马恢复正常。
面试加分秘籍
- 排查口诀:“一查进程二查线,jstack日志看得见,Arthas神器来相助,定位代码最关键”
- 反杀提问:当面试官问完时,可以反问:“咱们系统当前的线程池参数配置是怎样的?有考虑过动态调整吗?”
- 数据说话:提到处理过2000QPS下的CPU抖动问题,优化后GC次数下降80%
最后提醒各位:CPU爆满就像程序员的“高血压”,平时不注意代码健康,关键时刻就要“住院抢救”。记住,预防永远比排查更重要!
本文暂时没有评论,来添加一个吧(●'◡'●)