
“警告:服务器 prod-web-01 CPU使用率持续100%!” 当这条告警信息在凌晨三点划破你的手机屏幕时,相信我,那一刻你的困意全无,肾上腺素会瞬间飙升。CPU,作为服务器的“中央大脑”,一旦它的占用率持续“爆表”,就意味着你的网站可能会变得响应迟缓、应用处理能力下降,甚至完全卡死,导致用户无法访问,业务中断。这对于任何一个线上服务来说,都是不能承受之重。
但是,遇到CPU 100%就一定是坏事吗?也未必。咱们得先分清,这“大脑”是在高效地进行一场复杂的“头脑风暴”(比如正在进行视频转码、科学计算等高强度任务),还是被某个“无解的难题”(比如代码死循环)或者“繁杂的琐事”(比如疯狂等待磁盘I/O)给卡住了,导致“精神过载”,无法处理其他正常请求。前者是“过劳”,后者才是“发烧”。而我们今天这本手册,就是要教你如何快速诊断并治好这“高烧不退”的毛病!
第一步:“快照”现场——用top/htop揪出“头号嫌犯”
当CPU 100%的告警传来,你的第一反应,应该是立刻SSH登录到服务器,执行top或者更友好的htop命令。这就像警察到达案发现场,第一件事就是拉起警戒线,快速拍下“现场快照”,找出那个最可疑的“家伙”。
打开top命令后,你需要重点关注几列信息:
%CPU: 按下大写的P键,top会按CPU使用率从高到低排序。排在最前面的那个进程,就是咱们的“头号嫌犯”!记下它的PID(进程ID)和USER(所属用户)。Load Average(平均负载):
top右上角的一串数字,分别代表1分钟、5分钟、15分钟的系统平均负载。如果这个数值持续高于你的服务器CPU核心数,那说明系统确实处于高负载状态。CPU时间分布(
%us,%sy,%wa等):%us(user): 用户空间程序消耗的CPU。如果这个值很高,说明是你的应用程序(比如Java、Python、PHP等)在疯狂计算。%sy(system): 内核空间消耗的CPU。如果这个值很高,说明进程在进行大量的系统调用,比如频繁的I/O操作。%wa(I/O wait): CPU等待I/O操作(比如读写磁盘、网络)完成的时间。如果这个值很高,说明CPU其实没在“计算”,而是在“苦等”慢吞吞的硬盘或网络,瓶颈不在CPU本身,而在I/O。%id(idle): CPU空闲时间。当CPU 100%时,这个值应该接近于0。
打个比方: top就像一个项目经理,他不仅能告诉你“小明(某个进程)今天最忙”,还能告诉你小明的时间都花在了“做自己的项目(%us)”、“帮行政跑腿(%sy)”还是“等快递(%wa)”上。
第二步:深度“审讯”——层层剥茧分析“嫌犯”进程
锁定了“头号嫌犯”的PID后,咱们就得开始“深度审讯”,看看它到底在“忙活”些啥。根据进程类型的不同,我们的“审讯”手段也各不相同:
情况一:如果“嫌犯”是你的Java应用程序(比如Tomcat、SpringBoot)
这是最常见的情况。一个Java进程CPU飙高,通常是里面某个线程出了问题。
找出最耗CPU的“具体员工”(线程):
执行
top -H -p <PID>,-H参数会显示该进程下的所有线程。同样按P排序,找到那个%CPU最高的线程,记下它的ID(通常显示为LWP,轻量级进程ID)。查看“员工”在忙啥——打印线程堆栈:
将刚才找到的线程ID(LWP)转换成十六进制:
printf "%x\n" <LWP_ID>,得到一个十六进制值,比如a1b2。使用JDK自带的
jstack工具,打印出Java进程的堆栈信息,并用grep筛选出我们关心的那个线程:jstack <PID> | grep <十六进制线程ID> -A 30。-A 30表示打印出匹配行及其后的30行。这时,你通常就能从打印出的Java代码堆栈中,清晰地看到是哪个类的哪个方法正在被反复执行,很可能就是一个死循环或者一个极其耗时的操作!
情况二:如果“嫌犯”是数据库进程(如mysqld, postgres)
数据库CPU飙高,十有八九是有“慢查询”或者“锁竞争”在作祟。
登录到你的数据库。
查看当前活跃的“查询任务”:
MySQL: 执行
SHOW FULL PROCESSLIST;。关注那些Time列数值很大、State列显示异常(比如Copying to tmp table,Sorting result等)的查询。PostgreSQL: 查询
pg_stat_activity视图。分析“慢查询”的执行计划: 找到那个耗时的SQL语句后,使用
EXPLAIN <你的SQL语句>来分析它的执行计划,看看是不是没有用上索引导致了全表扫描,或者JOIN的姿势不对。
情况三:如果“嫌犯”是系统进程或未知程序
遇到这种情况,要多留个心眼,排查它是不是“不速之客”(比如病毒、挖矿程序)。
strace -p <PID>: 这个命令能实时跟踪进程的系统调用,看看它在和操作系统“聊”些什么,是在疯狂读写文件,还是在建立网络连接。lsof -p <PID>: 这个命令能列出该进程打开了哪些文件。通过查看它打开的文件,可以推断它的工作内容和目的。检查程序路径:
ll /proc/<PID>/exe,看看这个进程的可执行文件到底藏在哪儿。如果在一个非常可疑的目录下(比如/tmp),并且文件名奇奇怪怪,那就要高度警惕了。
第三步:关注“周边环境”——排查高I/O等待与中断
有时候,top显示CPU使用率很高,但仔细一看,是%wa(I/O等待)这一项特别高。这意味着CPU这个“CEO”其实很闲,但他手下的“快递员”(磁盘I/O)和“通讯员”(网络I/O)忙不过来,CEO只能干等着,导致看起来“很忙”。
诊断磁盘I/O瓶颈:
iostat -x 1 5:查看每个磁盘设备的I/O统计信息。重点关注%util(设备繁忙程度)、await(平均等待时间)和svctm(平均服务时间)。如果%util接近100%,说明磁盘已经到性能极限了。iotop:类似于top,但它能按I/O使用量对进程进行排序,帮你直接找到是哪个进程在疯狂读写磁盘。诊断网络I/O瓶颈:
sar -n DEV 1 5或nload:查看网络接口的实时流量,看看是不是带宽已经被打满了。
“对症下药”:从代码优化到系统调优的“组合疗法”
找到了病根,接下来就是“开药方”了。解决CPU 100%的问题,通常需要一套“组合拳”:
应用层面(治本):
优化代码逻辑: 修复死循环,优化算法,减少不必要的计算。
SQL优化: 为查询添加合适的索引,改写低效的SQL语句。
引入缓存: 对于高频访问但不常变化的数据,使用Redis、Memcached等缓存技术,大大减轻数据库压力。
异步化处理: 将那些耗时的、非核心的业务逻辑(比如发送邮件、生成报表)异步化,放到消息队列里去处理。
系统层面(治标/缓解):
硬件升级: 如果确实是业务量大导致资源不足,那就得考虑加CPU核心、加内存、换更快的SSD硬盘了。
内核参数调优: 对于高并发场景,可能需要调整一些Linux内核参数(通过
sysctl),比如网络连接数、文件句柄数等。但这需要专业知识,切忌盲目修改。调整进程优先级: 使用
nice和renice命令,降低非核心进程的优先级,确保核心业务能优先获得CPU资源。架构层面(长远之计):
负载均衡: 如果单台服务器扛不住,就用负载均衡器(如Nginx、HAProxy、云服务商的LB)将流量分发到多台服务器上。
服务拆分: 将庞大的单体应用,拆分成职责单一的微服务,隔离故障,方便独立扩容。
“防患于未然”:观图数据 监控如何让你成为“预言家”?
与其每次都等到CPU 100%了再去当“救火队员”,不如借助专业的监控平台,比如“
科学的告警阈值: 不要等到100%才告警!可以设置一个更灵敏的阈值,比如“CPU使用率连续5分钟超过85%”就触发告警,让你有更充足的时间去介入。
历史趋势分析: 监控平台能记录下你服务器CPU使用率的历史曲线。通过分析这些趋势,你很容易发现问题是否具有周期性。比如,是不是每天下午3点CPU都会飙升?那很可能就是某个定时任务或业务高峰期导致的,可以提前准备预案或进行优化。
多维度关联分析: 最强大的地方在于,专业的监控平台能将CPU使用率、内存、磁盘I/O、网络流量等多个指标的图表放在同一个时间轴上进行对比。你一眼就能看出,这次CPU飙升,是不是伴随着网络请求的激增,或者是某个磁盘的疯狂读写?这种关联分析,能让数据自己讲出“因果故事”,大大缩短你定位问题的时间。
验证优化效果: 当你进行了一系列优化后,监控平台的数据曲线,就是检验你优化成果的最直观、最客观的“成绩单”。
下一次,当CPU 100%的告警再次划破宁静,希望你不再是那个手心冒汗、心头一紧的“救火队员”,而是一位胸有成竹、思路清晰的“现场指挥官”。手握top、jstack、iostat这些诊断“利器”,再配合上专业监控平台提供的“全景作战地图”,任何企图让你的服务器“大脑过热”的性能瓶颈,都将无所遁形。
毕竟,在2025年,一个优秀的运维工程师,不仅要懂得如何在火光冲天时力挽狂澜,更要懂得如何在风平浪静时,就预见并消弭那些可能燃起大火的星星之火,不是吗?


豫公网安备41160202000677