Linux服务器CPU飙到100%,我是如何一步步定位的?

admin 2026-07-12 04:51:29 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文提供Linux服务器CPU飙升至100%时的系统化排查方法,强调先确认告警信息而非盲目重启。通过mpstat、vmstat等工具分析CPU时间分布,定位高CPU进程并深入线程级别。针对用户态、内核态、I/Owait及虚拟机steal等不同场景,给出具体命令和证据链建立步骤。同时涵盖容器和Kubernetes环境的特殊注意事项,是一份实用的生产环境故障排查指南。 综合评分: 90 文章分类: 实战经验


cover_image

Linux 服务器 CPU 飙到 100%,我是如何一步步定位的?

点击关注👉 点击关注👉

马哥Linux运维

2026年7月11日 13:00 广东

在小说阅读器读本章

去阅读

Linux 服务器 CPU 飙到 100%,我是如何一步步定位的?

CPU 使用率突然达到 100% 时,最容易犯的错误是看到一个高 CPU 进程就立即重启。重启可能暂时恢复服务,但也会清掉现场,并且无法回答三个关键问题:究竟是一个核心跑满还是整机跑满,CPU 时间消耗在用户态还是内核态,以及高 CPU 是根因还是其他故障的结果。

本文给出一套可以在生产环境执行的排查顺序。示例以 systemd 管理的 Linux 服务器为主,命令适用于常见的 RHEL、Rocky Linux、AlmaLinux、Ubuntu 和 Debian 系统。不同发行版的软件包名称可能不同:RHEL 系通常通过 dnf install sysstat procps-ng 安装工具,Ubuntu/Debian 通常通过 apt install sysstat procps 安装。安装软件会改变系统状态,生产环境应先确认软件源、变更窗口和主机管理规范。

一、先定义“CPU 100%”到底是什么

“CPU 100%”可能来自监控平台、top、容器面板或云厂商控制台,不同来源的分母并不一致。

  • 在一台 8 核服务器上,单线程程序占满一个逻辑 CPU,top 中该进程可能显示约 100%,但整机平均使用率只有约 12.5%。

  • top

    默认的进程 CPU 百分比可能以单个逻辑 CPU 为 100%;按 I 可在部分 procps-ng 版本中切换 Solaris/Irix 模式,实际行为应以本机 top 帮助为准。

  • Prometheus 中常用 node_cpu_seconds_total 计算 CPU 忙碌比例,但最终指标名和标签要以实际 exporter 暴露的指标为准。

  • 容器中的 100% 可能表示达到了 cgroup 配额,并不代表宿主机全部 CPU 已耗尽。

因此,第一步不是找进程,而是确认告警时间、持续时长、统计对象和采样周期。记录以下信息:主机名、业务实例、告警开始时间、是否仍在持续、监控查询语句、最近一次发布或配置变更时间。后续日志、指标和命令输出必须围绕同一时间窗口对齐。

二、现场保护与信息收集

先登录正确的主机并确认时间。不要只看终端提示符判断环境。

bash

hostnamectl
date --iso-8601=seconds
uptime

uptime 同时给出运行时长和 1、5、15 分钟 load average。负载不是 CPU 使用率:它通常包含正在运行以及等待不可中断资源的任务。高负载可能由 CPU 竞争引起,也可能由块设备、NFS 等 I/O 等待引起。

查看逻辑 CPU 数量和拓扑:

bash

lscpu
nproc

随后做短时间、低侵入采样。不要只截一张 top:瞬时峰值可能刚好落在采样点上,也可能被平均值掩盖。

bash

LC_ALL=C top -b -d 1 -n 10 > /tmp/top-$(date +%Y%m%d-%H%M%S).txt
vmstat 1 10
mpstat -P ALL 1 10
pidstat -u -r -d -w 1 10

这些命令主要是读取状态,通常风险较低,但采样工具自身也有开销。在已经严重过载的主机上,先执行 topvmstat 等轻量命令,谨慎使用 perf record、长时间 strace 或高频采样。

如果 /tmp 空间紧张,应改用经过确认的诊断目录。写文件前先检查:

bash

df -h /tmp
df -i /tmp

不要为了采样直接删除历史日志。清理日志属于高风险操作,可能破坏证据和审计链;如必须处理,应先归档、校验备份、明确保留范围并使用日志系统既定的轮转流程。

三、用系统级指标做初步判断

1. 看 CPU 时间花在哪里

mpstat 常见字段包括:

  • %usr

    :普通用户态程序消耗的 CPU 时间。

  • %sys

    :内核态消耗的 CPU 时间。

  • %iowait

    :逻辑 CPU 空闲且系统存在未完成磁盘 I/O 请求的时间比例。它不是“磁盘使用率”,也不能独立证明磁盘是根因。

  • %irq

    %soft:硬中断和软中断时间。

  • %steal

    :虚拟机等待宿主机调度物理 CPU 的时间。

  • %idle

    :空闲时间。

下面只用于说明格式,不代表任何真实环境。

示例输出:

text

Average:     CPU    %usr   %nice  %sys  %iowait  %irq  %soft  %steal  %idle
Average:     all   82.00    0.00  12.00     1.00  0.00    1.00    0.00   4.00

如果 %usr 长期很高,优先找业务进程和计算热点;如果 %sys 高,检查系统调用、锁竞争、网络包处理或频繁上下文切换;如果 %soft 高,结合网卡包率、丢包和软中断分布检查网络路径;虚拟机 %steal 高则需要结合云平台或宿主机侧指标,单靠来宾系统无法得出最终根因。

2. 看运行队列与上下文切换

vmstat 1 10 的第一行通常是自开机以来的平均值,分析实时问题时重点看后续行。

示例输出:

text

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa st
12  0      0 812344  24576 921600    0    0     0    20 9500 28000 86 12  2  0  0

关键字段的判断方式如下:

  • r

    是可运行任务数。持续明显高于逻辑 CPU 数,说明运行队列存在竞争,但短时超过并不一定异常。

  • b

    是处于不可中断睡眠状态的任务数,持续升高要检查 I/O 或内核等待。

  • cs

    是每秒上下文切换次数,必须与主机历史基线比较,不能凭一个绝对值定性。

  • us

    syidwast 分别对应用户态、内核态、空闲、I/O wait 和 steal。

3. 回看告警发生时的历史数据

如果 sysstat 已提前启用,可以使用 sar 回溯。当天数据通常位于 /var/log/sa/saDD 或 /var/log/sysstat/saDD,具体路径取决于发行版配置。

bash

sar -u -s 14:00:00 -e 14:30:00
sar -q -s 14:00:00 -e 14:30:00

如果读取指定文件:

bash

sar -u -f /var/log/sa/sa10

不要假设系统一定保留了历史数据。sar 未启用时无法事后恢复之前的 CPU 采样,应转向监控平台、应用日志和变更记录。

四、从进程定位到线程

先按 CPU 使用率列出进程,并保留完整参数:

bash

ps -eo pid,ppid,user,stat,psr,pcpu,pmem,etime,lstart,comm,args --sort=-pcpu | head -n 30

这里需要关注的不只是 %CPU

  • PID

    PPID 用于判断进程归属和父子关系。

  • PSR

    表示进程最近运行过的逻辑 CPU,不代表绑定关系。

  • STAT

    中 R 表示正在运行或可运行,D 表示不可中断睡眠,Z 表示僵尸进程。

  • ETIME

    LSTART 用于判断进程是否与故障窗口或发布操作对齐。

  • ARGS

    可帮助区分同名进程,但命令行可能包含敏感参数,归档和分享前需要脱敏。

假设已确认目标 PID 为 $PID,先把它替换成实际数字:

bash

PID=12345
ps -p "$PID" -o pid,ppid,user,stat,psr,pcpu,pmem,etime,lstart,cmd
readlink -f "/proc/$PID/exe"
tr&nbsp;'\0'&nbsp;' '&nbsp;<&nbsp;"/proc/$PID/cmdline";&nbsp;printf&nbsp;'\n'
cat&nbsp;"/proc/$PID/status"
cat&nbsp;"/proc/$PID/limits"

PID=12345 是占位示例,必须替换为现场确认的 PID;不要复制后直接操作未知进程。

多线程程序还要继续定位线程。只看进程总 CPU,无法区分单线程死循环和线程池整体繁忙。

bash

top -H -p&nbsp;"$PID"
pidstat -t -u -p&nbsp;"$PID"&nbsp;1 10
ps -L -p&nbsp;"$PID"&nbsp;-o pid,tid,psr,stat,pcpu,comm&nbsp;--sort=-pcpu

TID 是 Linux 线程 ID。Java 线程转储中的 nid 常以十六进制显示,可把十进制 TID 转换后匹配:

bash

TID=12367
printf&nbsp;'0x%x\n'&nbsp;"$TID"

对于 Java 应用,可在 JDK 工具可用且权限允许时采集线程转储:

bash

jcmd&nbsp;"$PID"&nbsp;Thread.print&nbsp;-l >&nbsp;"/tmp/jcmd-thread-$PID-$(date +%Y%m%d-%H%M%S).txt"

jcmd 必须以有权附加到目标 JVM 的用户运行。线程转储会增加短时开销,文件也可能包含业务类名、路径和锁信息,应按敏感诊断数据管理。不要默认用 kill -3,因为其输出位置取决于 JVM 标准错误流和服务配置,容易找不到或冲击日志。

五、围绕不同 CPU 类型建立证据链

场景一:用户态 CPU 高

用户态高通常来自计算密集逻辑、异常循环、请求量上升、序列化压缩、正则回溯、加密或垃圾回收等。不能只因为某个进程排在第一就认定代码有问题,还要同时回答:请求量是否增长、单请求耗时是否变化、线程热点是否稳定、变更时间是否吻合。

可以先观察进程级上下文切换和缺页:

bash

pidstat -u -r -w -p&nbsp;"$PID"&nbsp;1 10

如需函数级热点,Linux perf 是常用工具,但它可能受 kernel.perf_event_paranoid、调试符号、容器权限和内核配置限制。先做短时、低频采样:

bash

perf top -p&nbsp;"$PID"

或保存 30 秒采样:

bash

perf record -F 99 -g -p&nbsp;"$PID"&nbsp;--&nbsp;sleep&nbsp;30
perf report

perf record 会写入当前目录下的 perf.data,执行前确认目录空间和数据合规要求。采样会带来额外开销,影响范围是目标进程及采样所在主机;应先在单实例灰度,限制频率和持续时间。若业务延迟、CPU 或系统稳定性进一步恶化,立即终止采样并删除本次诊断任务,而不是继续扩大采样范围。

场景二:内核态 CPU 高

%sys 或 %soft 高时,先看是否伴随高系统调用率、上下文切换、网络包率或内核日志异常。

bash

pidstat -w -p ALL 1 10
cat&nbsp;/proc/softirqs
cat&nbsp;/proc/interrupts
journalctl -k --since&nbsp;'-30 min'&nbsp;--no-pager

两次读取 /proc/softirqs 的差值比单次累计值更有意义。不要看到某个 CPU 的累计数字大就直接下结论,因为累计值受运行时长和中断亲和性影响。

如果怀疑系统调用风暴,可短时间统计目标进程:

bash

timeout&nbsp;15s strace -f -c -p&nbsp;"$PID"

附加 strace 会影响目标进程时序,对高频系统调用程序影响尤其明显。影响范围是目标 PID 及其被跟踪线程;执行前应确认有可替代实例、当前错误率和延迟仍可接受,并先在灰度实例验证。生产主实例上不应长时间运行逐行 strace。出现延迟放大时可按 Ctrl-C 终止,或由 timeout 自动结束;终止跟踪不会终止被跟踪进程。

场景三:I/O wait 高但被误判成 CPU 高

如果 %iowaitb、块设备延迟同时上升,CPU 图表的“非空闲”比例可能很高,但根因应转向存储链路。

bash

iostat -xz 1 10
pidstat -d -p ALL 1 10

关注 iostat 中的 r/sw/sr_awaitw_await、队列和设备忙碌程度,但字段会随 sysstat 版本和设备类型变化。%util 接近 100% 对传统单队列设备有参考意义,对现代并行存储、RAID 和虚拟块设备不能单独用于判定饱和。必须与应用延迟、吞吐、队列、内核日志和存储侧指标交叉验证。

场景四:虚拟机 steal 高

当 %steal 持续升高,而来宾系统没有对应的高 CPU 进程,说明虚拟 CPU 在等待宿主机调度。证据应包含 mpstat/sar 的 steal 时间、云监控或虚拟化平台的宿主资源争用信息,以及同一时间的业务延迟。修复可能涉及迁移实例或调整宿主资源,这属于有中断或容量风险的操作,必须走云平台或虚拟化平台的变更流程。

六、容器和 Kubernetes 场景不能只看宿主机

先确认进程是否位于 cgroup 中:

bash

cat&nbsp;"/proc/$PID/cgroup"
systemd-cgls
systemd-cgtop

cgroup v2 可读取目标 cgroup 下的 cpu.statcpu.max 和 cpu.pressure。路径必须根据 /proc/$PID/cgroup 实际结果确定,不能把示例路径原样复制:

bash

CGROUP_PATH=/sys/fs/cgroup/example.slice/example.service
cat&nbsp;"$CGROUP_PATH/cpu.stat"
cat&nbsp;"$CGROUP_PATH/cpu.max"
cat&nbsp;"$CGROUP_PATH/cpu.pressure"

CGROUP_PATH 是占位符,需要替换为目标进程实际所属的 cgroup 目录。cpu.max 的第一个值为配额、第二个值为周期;max 表示未设置配额。cpu.stat 中是否包含 nr_throttledthrottled_usec 等字段与 cgroup 版本和内核有关。

Kubernetes 中必须明确命名空间。以下以 $NAMESPACE 和 $POD 为占位符,先替换后执行:

bash

NAMESPACE=production
POD=example-pod
kubectl -n&nbsp;"$NAMESPACE"&nbsp;top pod&nbsp;"$POD"&nbsp;--containers
kubectl -n&nbsp;"$NAMESPACE"&nbsp;describe pod&nbsp;"$POD"
kubectl -n&nbsp;"$NAMESPACE"&nbsp;get pod&nbsp;"$POD"&nbsp;-o yaml

kubectl top 依赖 Metrics Server,只提供近期资源值,不等同于历史监控。检查容器 resources.requests.cpu 和 resources.limits.cpu,再结合运行时或监控中的节流指标。Prometheus 常见指标包括 container_cpu_usage_seconds_totalcontainer_cpu_cfs_throttled_seconds_total 和 container_cpu_cfs_throttled_periods_total,但必须注明:以实际 exporter 暴露的指标为准。

高节流不一定说明节点 CPU 耗尽,它可能只是容器 CPU limit 太低。修改 Deployment 的资源限制会触发工作负载滚动更新,影响范围是该控制器管理的 Pod;执行前检查副本数、PodDisruptionBudget、可用容量、发布策略和当前错误率。先修改测试环境或单个灰度工作负载,验证吞吐、延迟、节流和节点余量后再扩大范围。回滚应恢复原清单或使用版本化发布系统回退到上一版本,不能依赖临时手工修改。

七、如何形成可复核的根因结论

一个合格结论至少包含四类证据:

  1. 时间证据:CPU 异常与发布、流量、任务或依赖异常发生在同一时间窗口。
  2. 资源证据:mpstatvmstatpidstat 或监控表明 CPU 时间具体消耗在哪一类。
  3. 对象证据:进程、线程、容器或函数热点稳定指向同一执行路径。
  4. 反证排除:存储等待、虚拟化 steal、CPU 配额节流或监控口径错误已被检查。

例如,不能写“某 Java 进程 CPU 最高,所以它是根因”。更完整的表达应是:在告警窗口内整机 %usr 持续升高,运行队列超过逻辑 CPU 数;目标 JVM 占用主要 CPU,固定线程在多次采样中保持高占用;线程转储和采样热点指向同一代码路径;同时请求量、I/O wait 和 steal 未出现同幅变化。是否进一步归因到具体代码缺陷,还要结合应用日志、调用参数和版本变更确认。

八、修复时先选最低风险动作

修复动作应与证据对应,常见顺序是:

  • 异常流量导致:在已有网关或负载均衡机制中限流、降级或隔离特定入口。
  • 后台任务导致:通过任务系统暂停或降低并发,而不是直接杀掉所有工作进程。
  • CPU limit 过低:在确认节点容量后调整单个工作负载并灰度发布。
  • 新版本代码热点:回滚到已验证版本,保留现场样本供后续修复。
  • 单实例失控且无在线控制手段:先摘除流量,再考虑优雅停止或重启。

重启服务属于高风险操作,必须补齐以下控制项:

  • 影响范围

    :明确是单实例、整组服务还是有状态节点,确认是否会中断连接、丢失内存队列或触发选主。

  • 执行前检查

    :确认健康实例和剩余容量,检查负载均衡摘流、在途任务、依赖方重试策略及当前错误率。

  • 备份方式

    :保存诊断采样、服务日志、配置版本、线程转储和必要的核心转储;有状态服务按其官方流程备份数据。

  • 灰度方法

    :只处理一个已摘流实例,优先使用应用提供的优雅退出机制。systemd 服务可先查看 systemctl status SERVICE 和单元配置,SERVICE 必须替换为真实单元名。

  • 验证方式

    :检查进程启动状态、健康检查、错误率、P95/P99 延迟、吞吐、CPU、运行队列和业务功能。

  • 回滚方案

    :若重启包含版本或配置变更,应能恢复原制品和原配置;若实例无法恢复,重新摘流并将流量切回健康实例。

不要把 kill -9 当成常规修复。SIGKILL 不给进程清理资源、刷新缓冲区或完成优雅退出的机会。只有在优雅停止失败、影响范围明确并且数据一致性方案已确认时,才考虑强制终止。

九、修复后的验证不能只看 CPU 降了

修复后至少观察一个覆盖正常业务波动的窗口。短暂下降可能只是流量被切走或进程刚启动尚未预热。

bash

mpstat -P ALL 1 10
vmstat 1 10
pidstat -u -r -d -w 1 10

同时验证:

  • CPU 的 %usr%sys%iowait%steal 是否恢复到同类时段基线。
  • 运行队列和上下文切换是否回落。
  • 目标进程或线程热点是否消失。
  • 请求量是否恢复,避免用“没有流量”解释资源下降。
  • 错误率、超时率、吞吐和 P95/P99 延迟是否正常。
  • 容器 CPU 节流是否改善,节点是否仍有足够余量。
  • 修复后是否出现内存、磁盘或下游依赖压力转移。

若修复无效,应按预案恢复原配置或原版本,并重新检查最初假设。回滚本身也要验证业务健康,不能以命令返回成功作为完成标准。

十、复盘与长期治理

复盘应保留原始证据和明确时间线,而不是只记录“重启后恢复”。建议补齐以下能力:

  • 为 CPU 用户态、内核态、I/O wait、steal、运行队列和容器节流分别建立监控,避免一个总 CPU 图覆盖所有语义。Prometheus 指标以实际 exporter 暴露的指标为准。
  • 保留足够时间的进程级或容器级历史数据,并统一主机、容器、应用和发布系统的时钟。
  • 对定时任务、批处理和线程池配置建立变更审计,避免并发参数无上限增长。
  • 为服务准备可验证的限流、降级、摘流、优雅退出和版本回滚流程。
  • 在压测或预发布环境建立 CPU 基线,记录正常请求量下的 CPU、延迟、吞吐和运行队列。
  • 对高 CPU 告警增加持续时间和业务指标关联,减少单个瞬时采样造成的误报。

CPU 100% 不是根因描述,而是调查入口。可靠的排查路径是先确认口径和时间窗口,再判断 CPU 时间类型,从系统定位到进程和线程,最后用日志、指标、采样热点与变更记录闭环。只有证据链能够被其他工程师复核,修复和复盘才真正有价值。

文末阅读福利

仅目前来说,无论是运维人转型提升,还是零基础想转行IT,最好的岗位就是云计算运维&SRE岗位。

为了帮助大家早日快速入门云计算运维领域,给大家整理了一套【最新运维资料】高级运维工程师必备技能资料包(文末一键免费领取),内容有多详实丰富看下图!

1.38张最全工程师技能图谱

2.面试大礼包

3.Linux书籍

内容比较多,就不一一展示了

以上所有资料获取请扫码:

识别上方二维码

备注:2026最新运维资料

100%免费领取

(是扫码领取,不是在公众号后台回复,别看错了哦)


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:马哥Linux运维 点击关注👉 点击关注👉《Linux 服务器 CPU 飙到 100%,我是如何一步步定位的?》

评论:0   参与:  0