Linux 服务器 CPU 高负载排查实战:从 load average 到进程定位

前言:服务器卡顿,先分清是网络还是 CPU

个人站长最常遇到的场景,就是网站突然变慢,SSH 连接敲命令都一卡一卡的。很多人第一反应是换带宽、加内存,其实大部分时候问题出在 CPU 被某个进程吃满了。排查 CPU 高负载是 Linux 运维的基本功,本文从 load average 的解读讲起,一步步带你定位到具体的进程,并给出常见病因的处置方法。整篇文章的操作在 CentOS 7、Ubuntu 20.04 等主流发行版上都通用,只需要一个 root 权限的 SSH 终端。

第一步:看懂 load average,判断负载到底高不高

登录服务器后,第一件事是执行 uptime 命令,它会输出系统运行时间和最近 1 分钟、5 分钟、15 分钟的平均负载。load average 表示一段时间内处于可运行状态和不可中断睡眠状态的进程平均数,它并不直接等于 CPU 使用率。判断负载是否过高的标准是和 CPU 核心数对比:如果负载值长期大于核心数,说明任务在排队;如果只有核心数的一半左右,即使看起来数字不小,系统其实很轻松。

uptime
# 输出示例
# 14:23:01 up 32 days,  4:12,  1 user,  load average: 8.12, 6.45, 3.20

上面这台是四核服务器,1 分钟负载 8.12 明显超标,5 分钟负载 6.45 也在排队,而 15 分钟只有 3.20,说明负载是刚刚涨起来的,属于突发型问题,排查方向应该放在最近启动或最近变活跃的进程上。反过来,如果 15 分钟负载一直很高而 1 分钟反而低,说明系统已经持续过载很久,可能是配置不足或者存在长期泄漏的进程,需要从整体架构上考虑。另外要记住,负载高不一定代表 CPU 忙,磁盘 IO 等待和内存换页同样会推高负载,这点后面会专门讲到。判断负载高低还有一个前提,就是确认服务器到底有几个核心。执行 nproc 或者 lscpu 可以查看 CPU 核心数,云服务器配置页里写的 vCPU 数通常就等于核心数。把 load average 除以核心数可以得到每核心负载:小于 0.7 属于健康区间,0.7 到 1 之间需要留意,长期大于 1 说明 CPU 已经过载。有些站长看到四核机器负载 3.0 就紧张,其实这个数值意味着每个核心平均才 0.75,系统还有余量,真正要警惕的是负载持续上涨的趋势,而不是单个瞬间的数值。

第二步:用 top 快速锁定可疑进程

确认负载确实偏高之后,执行 top 进入实时监控界面。进入后按大写 P 键让进程按 CPU 使用率排序,按大写 M 键可以按内存排序。重点关注 %CPU 列,正常情况下不会有进程持续占用接近 100% 的多核资源,如果某个进程的 CPU 时间一直飙升,它多半就是罪魁祸首。top 输出顶部还有一行 Tasks,其中 zombie 后面的数字代表僵尸进程数量,僵尸进程不消耗 CPU,但如果数量持续增长说明有父进程没有正确回收子进程,也需要处理。

top -bn1 | head -20
# 非交互模式跑一次,适合脚本里用
# 按 CPU 排序查看:top 进入后按 P

如果服务器上跑着多个网站,可以用 top 配合用户名过滤,快速确认是不是某个特定用户(比如 www-data 或 mysql)的进程在吃资源。执行 top 后按 u 键输入用户名,界面里就只会显示该用户的进程。对于个人站长来说,最常见的两种情况是:PHP-FPM 的 worker 进程集体飙高,以及 MySQL 的某个连接在跑慢查询。看到可疑进程后,记下它的 PID,下一步用更精细的工具确认它的行为。

第三步:vmstat 判断瓶颈是 CPU 还是磁盘 IO

top 只能看到进程层面,要判断系统瓶颈到底在 CPU、内存还是磁盘,需要用 vmstat。执行 vmstat 1 5 会每隔一秒采样一次,共输出五组数据。重点看这几列:r 表示等待运行的进程数,数值持续大于核心数说明 CPU 确实不够;b 表示处于不可中断睡眠的进程数,如果经常大于零,说明进程在等磁盘 IO;us 是用户态 CPU 占比,sy 是内核态占比,wa 是 IO 等待占比,id 是空闲占比。当 wa 很高而 us 不高时,说明磁盘读写拖了后腿,这时候盲目加 CPU 核心毫无意义,应该查磁盘。

vmstat 1 5
# 输出列:r  b  swpd  free  buff  cache  si  so  bi  bo  in  cs us sy id wa

还有两列值得注意:si 和 so 表示从交换分区换入换出的内存页数,如果这两个数字持续不为零,说明物理内存已经不够用,系统正在频繁换页,这种状态下负载也会虚高,但根因是内存而不是 CPU。cs 列是上下文切换次数,每秒几十万次的上下文切换通常意味着进程数量过多或者锁竞争严重。看完 vmstat 就能基本判断方向:r 高且 us 高是 CPU 问题,wa 高是磁盘问题,si so 持续非零是内存问题,接下来对症下药。

第四步:pidstat 和 mpstat 精确到进程与核心

vmstat 给出整体方向后,用 sysstat 工具包里的 pidstat 和 mpstat 做精确定位。如果系统还没装 sysstat,Ubuntu 用 apt install sysstat,CentOS 用 yum install sysstat。pidstat 1 5 会每秒输出一次每个进程的 CPU 使用明细,能直接看到是哪个 PID 在持续消耗 CPU,还能顺带观察进程的线程数和内存变化。mpstat -P ALL 1 5 则把每个 CPU 核心的使用率单独列出来,用于发现某个核心被打满而其他核心空闲的情况,这种问题通常出在单线程程序或者内核中断集中在某个核心上。

pidstat 1 5
# 按进程查看 CPU 明细,%CPU 列持续高的就是问题进程
mpstat -P ALL 1 5
# 查看每个核心的使用率,发现单核打满要留意

定位到具体 PID 后,用 ps 查看它的启动命令和启动时间,判断是不是正常业务进程。命令格式是 ps -p 进程号 -o pid,lstart,cmd。如果是你认识的业务进程,比如 php-fpm 或 mysqld,就去查它的日志和慢查询;如果是一个名字很怪、路径藏在 /tmp 或 /var/tmp 下的进程,那基本可以断定是挖矿木马或者被入侵后植入的后门,处理方法是先 kill 掉进程,再排查定时任务、SSH 公钥和系统用户,找到入侵入口彻底封堵,只杀进程不堵漏洞等于白干。

第五步:常见病因与处置对照

把个人服务器上常见的 CPU 飙高场景整理成清单,方便你对号入座。第一种是 PHP-FPM 全 worker 占满,通常由某个接口死循环、采集脚本失控或者被 CC 攻击触发,先看访问日志找异常请求,再临时调低 pm.max_children 并重启 PHP-FPM 止血。第二种是 MySQL 慢查询堆积,表现为 mysqld 的 CPU 高而网站响应极慢,开启慢查询日志定位 SQL,给大表补索引是最有效的解法。第三种是定时任务重叠,crontab 里某个脚本执行时间超过执行周期,导致多个实例同时运行,处理办法是在脚本里加锁,防止并发执行。第四种是日志进程失控,比如访问量突增后 access.log 疯狂写入,rsyslog 或 logrotate 占用 CPU,配合日志切割和定期清理能解决。

还有一类隐蔽问题值得单独提醒:云服务器被入侵后植入挖矿程序,矿工会把进程伪装成系统进程名,比如 kswapd0、udevd 之类的名字,还会用 rootkit 隐藏进程,普通 ps 根本看不到。遇到这种情况,用 top 看 CPU 占用率最高的进程,再用 ls -l /proc/PID/exe 查看进程的真实可执行文件路径,伪装进程的真实路径往往在 /tmp 或者用户目录下。确认后先断网隔离,再清理定时任务和自启动项,最后修改所有密码和密钥,必要时直接重装系统,数据有备份的话重装是最省心的选择。

预防比排查更重要

高负载问题反复出现,说明缺少日常监控。对个人站长来说,不一定要上重型的监控系统,一个简单的 shell 脚本加 crontab 就够用:每五分钟检查一次 load average,超过阈值就发一封告警邮件,脚本内容就是读取 /proc/loadavg 再和阈值比较。进阶一点可以装 node_exporter 配合 Prometheus 和 Grafana,把 CPU、内存、磁盘、网络的曲线都画出来,平时多看看正常状态下的数值基线,等出问题时一眼就能看出哪里异常。另外,给服务器加上 swap 分区、合理设置 PHP-FPM 的进程数上限、给 MySQL 开启慢查询日志,都能减少 CPU 问题发生的概率。

小结

排查 CPU 高负载的思路可以总结成四句话:先用 uptime 看负载趋势判断问题性质,再用 top 找可疑进程,接着用 vmstat 区分 CPU、磁盘、内存三类瓶颈,最后用 pidstat 和 mpstat 精确定位到进程和核心。绝大多数个人服务器的 CPU 飙高都不是硬件问题,而是某个进程失控或者被入侵,找到它、处置它、补上监控,问题就能彻底解决。把这套流程多练几遍,下次网站再卡的时候,你就能在五分钟内给出答案,而不是干着急。

Last modification:September 7th, 2026 at 07:56 am

Leave a Comment