服务器CPU使用率长时间居高不下,轻则拖慢业务响应,重则导致宕机。很多运维同学看到CPU高就急着加机器,但如果不找到根因,加再多资源也扛不住。本文从一个实战排查者的角度,分享一套经过验证的排查思路,帮你一步步定位问题。
第一步:确认CPU负载数据,排除假象
不要只看“CPU起飞”就恐慌,先拿到准确数据。登录服务器,依次执行:top(看整体负载和占用率)、htop(更直观)、sar -u 1 5(看历史趋势)。特别关注us(用户态)、sy(系统态)、wa(IO等待)、st(被虚拟机偷走的时间)。如果us高,是应用问题;sy高,是系统调用频繁;wa高,则是磁盘IO瓶颈;st高,说明宿主机超卖严重。这一步能帮你确定问题方向。
第二步:找到吃CPU的“元凶”进程
使用top -o %CPU(按CPU降序),记下PID。也可以用ps aux --sort=-%cpu | head -10。对于Java应用,推荐top -Hp PID查看线程级别,然后使用jstack PID或pstack PID导出堆栈。如果进程是Python/Ruby/Node,则用strace -p PID -c -f统计系统调用频率。记录下异常进程的CPUs占用率、内存、启动时间,有助于判断是不是最近上线的新功能导致的。
第三步:深入进程内部,定位热点代码
光知道进程还不够,得揪出具体的代码行。常用三大利器:
- strace:
strace -p PID -c统计一次,看哪些syscall耗时最多;strace -p PID -e trace=network,write,read过滤关注点。如果发现大量epoll_wait或futex,说明可能是锁竞争或网络等待。 - perf:Linux性能剖析神器。
perf top -p PID实时显示进程内最耗CPU的函数;perf record -g -p PID -- sleep 30; perf report生成调用链火焰图。perf的采样数据能直接定位到动态库甚至内核函数。 - 火焰图:生成svg后用浏览器打开,看“平顶”区域就是热点。工具可以参考 Brendan Gregg 的 FlameGraph。
如果应用是Java,jstack导出的线程Dump配合top -H找到的线程ID(转换成十六进制),直接定位到具体的代码行号。Java常见CPU高原因:死循环、频繁Full GC(CMS或G1并发标记阶段)、大量正则匹配、高并发下的锁争用。
第四步:排查常见“病根”
根据多年经验,以下原因出现频率最高:
- 死循环或无限递归:常见于代码bug、配置错误导致while(true)跑飞。用strace看是否一直执行同一操作。
- 内存泄漏导致频繁GC:Java堆被占满后GC线程疯狂工作,吃掉CPU。查看
jstat -gcutil PID 1000,如果FGCT持续增长且YGC频繁,基本确认。使用MAT或jmap dump堆分析。 - 线程过多且锁争用:大量线程尝试获取锁,上下文切换飙高。用
vmstat 1观察cs列(context switch),如果超过几万甚至几十万,说明系统在大量线程调度上浪费CPU。可以通过减少线程池大小、优化锁粒度(如使用读写锁、分段锁)解决。 - 日志框架失控:debug级别日志打印大量字符串拼接,或异步日志线程被阻塞导致CPU升高。检查日志配置,限制输出级别。
- 定时任务或cron并发:很多业务在整点或整分钟启动大量定时任务,短时CPU冲高。排查crontab或业务调度框架,错峰执行。
- 恶意挖矿程序:如果看到陌生进程名如
xmrig、kdevtmpfsi,或者CPU被一个叫httpd但路径在/tmp的进程占满,大概率被入侵了。检查/proc/PID/exe路径,杀掉并清理残留文件。
第五步:系统层面微调与长期监控
如果确认不是业务代码问题,而是系统参数不合理:
- 调整进程优先级:
renice -n -10 -p PID让关键进程优先获得CPU,但慎用。 - 绑定CPU核心:
taskset -c 2,3 PID防止进程在不同核心间频繁迁移导致缓存失效。 - 优化内核参数:如果sy(系统态)高,比如大量中断或上下文切换,可以调整
net.core.rmem_default、vm.swappiness等。 - 升级硬件或拆分服务:如果是业务增长导致的常态CPU高,考虑水平扩容或迁移到更强CPU。
最后,一定要建立持续监控。使用Prometheus+Node Exporter采集CPU指标,设置告警阈值(比如持续15分钟大于85%)。当CPU高时自动保留一份top快照和strace结果,便于事后分析。
总结
CPU居高不下不是玄学,而是有章可循的工程问题。记住这个排查链路:确认数据→定位进程→分析热点→根因归类→系统优化。每次排查后记录问题和解决方案,慢慢积累成知识库。以后遇到类似问题直接对照“破案”,效率翻倍。