上一篇 下一篇 分享链接 返回 返回顶部

CPU 100%告警反复出现,怎样判断该调内核参数还是修复应用?

发布人:Minchunlin 发布时间:2026-10-04 20:19 阅读量:3

CPU 100%告警本身只能说明“CPU时间被大量消耗”,不能直接证明是内核参数不足,也不能直接证明应用代码有问题。先看这100%由 user、system、iowait、softirq 还是 steal 构成,再确认是单个进程、单个线程、数据库进程,还是整台主机共同升高,才能决定后续动作。

排查顺序应当是:先确认告警是否持续并保留现场,再区分CPU、内存、磁盘和网络压力;随后沿着进程、线程、应用请求和数据库语句逐层溯源。只有当系统指标明确指向连接队列、文件描述符、连接跟踪表等内核资源耗尽时,才考虑调内核参数。若某个应用线程、接口、定时任务或SQL持续消耗CPU,优先修复应用或查询,调参通常只是延后再次告警。

先确认“100%”到底代表什么

不同监控工具对CPU百分比的统计口径可能不同。整机CPU使用率达到100%,通常表示所有逻辑CPU的总计算能力基本被占满;而 top 中某个进程显示300%,可能表示它同时使用了约3个逻辑CPU。因此,不能只看告警标题或单个进程百分比。

先记录告警时间、持续时长、受影响的业务接口、部署变更和定时任务。排查时尽量不要一开始就重启服务、清理缓存或修改系统参数,否则可能丢失最有价值的现场信息。

可以先执行以下低风险检查:

date
uptime
nproc
top -b -n 1 | head -n 25

重点关注以下指标:

指标主要观察内容常见含义
load average与逻辑CPU数量比较,观察是否持续增长可能有CPU运行队列,也可能包含不可中断的磁盘等待
%us / user用户态程序消耗的CPU应用代码、数据库计算、压缩、加密、垃圾回收等
%sy / system内核态消耗的CPU系统调用、网络栈、文件系统、内存管理等
%wa / iowait等待磁盘或块设备完成I/O的时间磁盘延迟、查询I/O、日志写入或内存回收
%si / softirq软件中断消耗的CPU网络包处理、连接风暴、数据包转发等
%hi / irq硬件中断消耗的CPU网卡、存储设备或其他硬件中断压力
%st / steal虚拟机被宿主机暂时收回的CPU时间宿主机争用或虚拟化层资源不足
单个线程CPU是否只有一个线程长期占满一个核心单线程计算、锁竞争、循环或某个请求处理异常

load average 不能单独等同于CPU使用率。例如CPU使用率不高,但磁盘等待严重时,负载仍可能很高;反过来,多个线程持续计算时,CPU和负载可能同时升高。

按优先级保留现场

第一步:确认是尖峰还是持续性问题

如果CPU只在几秒内达到100%,随后恢复,常见原因包括定时任务、日志压缩、批量请求、缓存重建或监控采集。若告警反复出现,且每次都与固定时间、固定接口或固定任务相关,应优先查业务触发条件。

可以连续采集几组数据:

vmstat 1 5
mpstat -P ALL 1 5
pidstat -u -r -d -w -t 1 5

这些命令通常来自 procps 或 sysstat 工具包。如果命令不存在,不要直接猜测安装包名称,先确认系统发行版和软件源,再安装对应工具。

结果可以这样理解:

  • mpstat 显示所有核心都接近繁忙,且 %us 较高:倾向于应用或数据库的实际计算压力。
  • 只有一个核心接近100%,其他核心空闲:可能是单线程任务、线程绑定、锁竞争或应用并行度不足。
  • %sy、%si 明显升高:转向系统调用、网络包处理、文件系统或连接风暴。
  • %wa 较高:不要把它当成“CPU不够”,应继续查磁盘、内存和I/O路径。
  • %st 较高:虚拟机内部调参通常不能解决宿主机CPU争用。
  • vmstat 的 r 长期高于逻辑CPU数量:运行队列可能积压;但仍需结合CPU各状态判断。
  • vmstat 的 b 较高:有较多任务处于不可中断等待,常与磁盘或其他I/O有关。

第二步:确认是整机问题还是单一进程问题

使用进程和线程维度继续缩小范围:

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

如果已经找到进程PID,例如 12345,可以进一步查看线程:

top -H -p 12345
pidstat -p 12345 -u -r -d -w -t 1 5

这里的关键不是只看“哪个进程排在第一位”,而是观察:

  1. 该进程是否在告警开始后才升高;
  2. CPU消耗是否集中在一个线程;
  3. 进程的内存、读写和上下文切换是否同步异常;
  4. CPU下降时,业务延迟是否也恢复;
  5. 进程是否属于应用、数据库、日志组件或系统服务。

若某个应用进程长期占用大部分CPU,而磁盘、网络和内存压力并不明显,优先进入应用溯源;若数据库进程占用CPU,则要进一步看活动会话和慢查询,而不是先调Linux内核参数。

先分辨CPU、内存、磁盘和网络瓶颈

分支一:user CPU高,优先查应用或数据库

%us 较高通常表示程序真正消耗了计算资源。典型原因包括:

  • 请求量增加,但单次请求计算量没有下降;
  • 正则匹配、序列化、压缩、加密或图片处理耗时;
  • 代码出现高频循环、重复计算或异常重试;
  • 垃圾回收频繁;
  • 定时任务与在线请求同时运行;
  • 数据库执行了高成本排序、聚合、全表扫描或大量连接处理;
  • 线程数增加后发生竞争,导致上下文切换和无效工作。

此时应将CPU进程与业务指标对齐。至少同时看请求量、响应时间、错误率、并发数和发布记录。如果CPU与请求量同步增加,可能是容量或单位请求成本问题;如果请求量没有增加但CPU突然升高,更像是异常循环、重试、数据分布变化、定时任务或部署引入的回归。

应用侧建议按以下路径确认:

  1. 根据PID找到服务实例、部署版本和启动参数。
  2. 根据线程ID确认热点线程属于哪个模块。
  3. 对照应用日志中的接口、任务名、异常重试和批处理记录。
  4. 在可控时间窗口使用采样分析工具,确认CPU热点函数。
  5. 用同等请求量重新验证修复前后的单请求CPU成本。

生产环境不建议未经评估直接使用高开销的全量跟踪或调试器。采样分析通常比持续全量跟踪更适合在线排查;如果必须使用高开销工具,应先限定进程、持续时间和采样频率,并准备停止采集的方法。

分支二:数据库进程CPU高,优先修复SQL和访问模式

当数据库进程占用CPU较高,而应用进程CPU并不高,常见问题可能在数据库查询本身:

  • 查询条件选择性差,扫描了大量数据;
  • 排序、聚合、连接操作数据量过大;
  • 应用产生N+1查询;
  • 连接池配置导致并发查询过高;
  • 数据量增长后原有索引不再适用;
  • 同一条SQL因参数变化出现不同执行计划;
  • 失败请求被应用快速重试,形成查询放大。

数据库排查应同时查看活动会话、慢查询记录、执行耗时、扫描行数、锁等待和连接数。不要因为数据库CPU高就盲目增加连接数;连接数增加可能进一步放大CPU、内存和上下文切换压力。

如果数据库CPU并不高,但应用响应时间变长,应重点看数据库等待、磁盘延迟、锁竞争和网络往返,而不是把问题归类为CPU不足。SQL优化也不应只依据一条执行计划就直接改表结构,修改索引或查询前应确认数据量、写入成本、磁盘空间和回滚方案。

分支三:system、softirq或irq高,查系统调用和网络包处理

如果用户态CPU不高,但 %sy、%si 或 %hi 明显升高,方向就从业务计算转向内核路径。常见场景包括:

  • 短连接大量创建和关闭;
  • 网络连接或数据包数量突然增加;
  • 应用频繁调用文件系统、时间函数或进程间通信;
  • 大量小包导致软中断压力;
  • 日志写入、文件扫描或块设备请求异常;
  • 某个服务反复失败并快速重试。

可以先看网络和软中断概况:

sar -n DEV 1 5
ss -s
cat /proc/softirqs

如果系统没有 sar,可以使用网卡计数器和连接统计;如果需要更细的网卡信息,再确认 ethtool 是否可用:

command -v ethtool
ip -s link

这类问题需要区分“内核处理压力”和“应用制造压力”。例如短连接过多,既可能是连接队列或文件描述符不足,也可能是应用没有复用连接、上游超时太短或失败重试过快。只提高队列长度,不能减少连接创建和关闭本身。

分支四:iowait高,查磁盘和内存回收

当 %wa 明显升高时,CPU可能只是等待设备完成工作。建议检查:

iostat -xz 1 5
free -h
vmstat 1 5
df -h
df -i

重点看:

  • await:I/O请求从提交到完成的平均等待时间;
  • avgqu-sz:设备队列是否积压;
  • %util:设备忙碌程度,但不同设备和内核版本下解释不能机械套用;
  • 读写吞吐是否接近设备能力;
  • 文件系统空间和inode是否耗尽;
  • 内存是否紧张并触发频繁回收或交换。

如果磁盘延迟高,同时数据库、日志或应用进程有大量写入,先查具体I/O来源。如果内存不足导致交换,CPU告警可能只是内存压力的后果。此时调整CPU相关参数没有帮助,应先减少内存占用、控制并发、优化缓存或处理I/O瓶颈。

分支五:steal高,查虚拟化资源争用

虚拟机中的 %st 表示虚拟CPU想运行但暂时无法获得宿主机物理CPU。若该值在告警期间持续升高,通常应核查宿主机或云平台的CPU争用、实例配额和资源分配。

此时即使在虚拟机内调整调度参数,也无法凭空增加宿主机提供的计算时间。可以保留虚拟机内的进程和业务证据,再与资源平台侧确认;不要把steal时间误判成应用代码的user CPU。

分支六:网络异常不一定表现为CPU高

网络问题可能导致CPU升高,也可能只表现为响应变慢。需要区分:

  • 网络包量过大,导致softirq升高;
  • 连接建立过多,导致内核连接表或监听队列压力;
  • 丢包和重传导致应用重复发送;
  • 上游响应慢,应用线程大量等待;
  • 文件描述符或连接池耗尽;
  • 应用自身频繁创建短连接。

ss -s 可以帮助查看TCP连接总体状态。若要观察单个连接的更多信息,可以在明确目标连接后使用:

ss -ti

网络工具能说明连接状态和部分TCP统计,但不能证明业务代码没有问题,也不能仅凭连接数多就认定需要调大内核参数。连接数高可能是正常高并发,也可能是连接复用失效或请求超时造成的堆积。

什么时候才应该调内核参数

调参的前提是:已经找到明确的资源边界,并且应用行为本身合理或暂时无法立即修改。一个实用判断是:

  • 如果“某个进程或线程在做大量无效计算”,修应用;
  • 如果“数据库在执行高成本查询”,修SQL、索引或访问模式;
  • 如果“磁盘、内存或虚拟化层在等待”,处理对应资源;
  • 如果“请求已经合理,但内核限制导致合法请求被拒绝或排队”,才评估内核参数;
  • 如果没有对应的耗尽证据,不要因为CPU告警就批量修改sysctl。

常见参数与判断边界如下:

现象需要先确认的证据可能涉及的参数或限制不能忽略的边界
监听队列溢出、连接建立阶段排队应用监听队列、内核统计、应用accept能力net.core.somaxconn、应用监听backlog队列变大不代表应用处理能力变强
文件描述符耗尽进程打开文件数、ulimit、服务限制LimitNOFILE、进程软硬限制、系统文件表提高上限前要确认内存和连接泄漏
连接跟踪表耗尽nf_conntrack_count 接近 nf_conntrack_max,且业务确实使用该机制net.netfilter.nf_conntrack_max增大表会占用内存,不能解决短连接风暴
网络缓冲不足丢包、socket buffer不足、吞吐和延迟证据net.core.rmem_、net.core.wmem_等缓冲过大可能增加内存占用和排队延迟
交换或脏页回写造成I/O等待内存压力、交换活动、写回延迟vm.swappiness、脏页相关参数不能用它们掩盖内存不足或磁盘过慢
CPU被某个线程持续占满进程和线程热点明确通常不应优先调内核参数调度参数很少能修复业务热循环

先查看当前值和相关限制,不要直接复制网络文章中的整套参数:

sysctl net.core.somaxconn
sysctl net.netfilter.nf_conntrack_count 2>/dev/null
sysctl net.netfilter.nf_conntrack_max 2>/dev/null
ulimit -n
cat /proc/sys/fs/file-nr

检查某个服务进程的文件描述符限制:

cat /proc/12345/limits | grep -i "open files"
ls /proc/12345/fd | wc -l

这里的 12345 需要替换为实际PID。/proc/进程号/limits 反映的是该进程自身限制,不能用当前登录Shell的 ulimit -n 代替。

低风险验证与参数变更边界

如果证据明确指向某一项参数,可以先做临时、单项、可回退的验证。变更前应记录旧值、确认适用内核和服务模型,并评估影响范围。不要同时修改多个参数,否则无法判断哪个变化产生了效果。

例如只读取并临时验证监听队列上限:

old_somaxconn="$(sysctl -n net.core.somaxconn)"
echo "old net.core.somaxconn=${old_somaxconn}"

sudo sysctl -w net.core.somaxconn=2048

sysctl net.core.somaxconn

上面的数值只是示例,不是所有系统都适合使用的固定值。若验证没有改善,或出现内存、延迟、连接排队等副作用,应恢复原值:

sudo sysctl -w net.core.somaxconn="${old_somaxconn}"
sysctl net.core.somaxconn

如果验证有效,也不要立即把临时值写入全局配置。应先确认:

  • 应用是否确实设置了相匹配的监听队列;
  • 连接排队是否下降;
  • 应用accept速度是否足够;
  • CPU、内存和请求延迟是否没有恶化;
  • 重启后是否需要持久化;
  • 该参数是否受发行版、内核版本或服务管理方式影响。

需要持久化时,先备份现有配置,采用单独文件并记录变更原因、旧值、新值和回滚命令。修改系统配置属于高影响操作,应安排维护窗口或至少准备服务级回退方案。不要在没有备份的情况下直接覆盖系统配置,也不要使用 sysctl -p 盲目加载一整套未经验证的参数。

如何判断应用修复优先级

如果CPU 100%告警具有以下特征,应用修复通常比内核调优更重要:

  • 单个应用线程或进程稳定占用CPU;
  • CPU高峰与某个接口、任务或批处理同时发生;
  • 请求量没有明显增加,但单请求耗时和CPU成本升高;
  • 应用日志出现重试、异常循环或超时堆积;
  • 数据库慢查询或执行计划显示扫描、排序、聚合成本明显;
  • 调大队列、缓冲或文件描述符后,CPU仍然持续升高。

可以用“每个请求消耗多少CPU时间”作为辅助指标。假设某服务在每秒处理1000个请求时占用约4个逻辑核心,那么平均每个请求大约消耗:

4个核心 × 1秒 ÷ 1000个请求 ≈ 0.004个CPU秒/请求

如果请求量仍是每秒1000个,但CPU增加到8个核心,说明单请求CPU成本大致翻倍;此时更应寻找代码路径、数据量、序列化、压缩、查询或重试变化,而不是先提高系统上限。

如何判断应用修复优先级配图

对于数据库,也可以按同样思路比较单位查询成本。查询数量、扫描行数、平均耗时和CPU时间同时上升时,优化SQL或访问模式通常比增加连接数更有价值。

如何判断内核调优确实有必要

内核参数调优更适合以下场景:

  • 监听队列有明确溢出,而应用处理能力和上游请求速率合理;
  • 进程因文件描述符限制被拒绝,但确认不存在连接泄漏;
  • 连接跟踪表确实达到上限,且扩大容量后的内存成本可接受;
  • socket缓冲区被明确证明限制了吞吐,而不是网络链路、应用读取速度或丢包导致;
  • 内存和磁盘容量能够承担参数增大后的额外开销;
  • 参数变更能解释告警中的具体现象,并且有可观察的验证指标。

例如,监听队列问题的完整判断不能只有“连接数很多”。至少应同时确认监听端口、队列状态、连接建立失败或超时、应用accept速度和CPU状态。如果CPU user已经很高,说明应用处理不过来,此时单纯增大队列可能只会让更多请求在内核中等待。

文件描述符问题也类似。查看到打开文件数接近上限,只能说明限制可能存在,还要排除连接泄漏、日志文件未关闭、客户端连接未复用等应用问题。提高 LimitNOFILE 后,必须继续观察进程打开文件数是否持续增长。

一个可执行的排查顺序

可以按照以下顺序处理反复出现的告警,每一步都根据结果决定是否进入下一层:

一个可执行的排查顺序配图

  1. 保存现场:记录时间、持续时长、业务影响、部署和定时任务;采集 uptime、mpstat、vmstat、pidstat。
  2. 拆分CPU状态:确认是user、system、iowait、softirq、irq还是steal占主导。
  3. 定位进程和线程:用 ps、top -H、pidstat -t 确认是否存在单一热点。
  4. 排除资源等待:查看内存、交换、磁盘延迟、I/O队列、网络连接和软中断。
  5. 进入应用链路:把热点线程关联到接口、任务、异常日志、请求量和版本变更。
  6. 进入数据库链路:核对活动查询、慢查询、锁等待、连接数和执行计划。
  7. 核对内核限制:只针对已经出现的队列溢出、描述符耗尽、连接跟踪耗尽等证据检查参数。
  8. 单项验证:一次只改一个参数,记录旧值,限定影响范围,并观察业务指标。
  9. 决定长期动作:应用热点进入代码或SQL修复;资源边界问题才形成参数变更;虚拟化争用则转向宿主机资源处理。

修复后不能只看告警是否消失

一次CPU告警暂时恢复,不等于问题已经解决。修复或调参后,至少应在相近请求量、相近数据量和相近时间窗口内对比以下指标:

对比项需要确认的结果
CPU user/system/iowait/steal原来的主导异常是否消失,是否转移成新的瓶颈
单进程和单线程CPU热点线程是否下降,是否只是热点转移
请求量和响应时间吞吐是否保持,P95或P99延迟是否改善
错误率和超时队列变大后是否出现更多超时
内存和交换调大缓冲、连接表后是否产生额外内存压力
磁盘延迟和队列日志、数据库或回写是否变慢
网络连接与重传连接堆积、重传或短连接是否减少
数据库查询指标慢查询、扫描行数、锁等待和连接数是否改善

可以设置一个与业务相关的观察窗口,而不是只观察几分钟。若问题每天固定发生,应至少覆盖一次原有触发时段;若由发布或流量触发,则应在相近负载下比较。参数变更后CPU下降但请求延迟、错误率或内存占用上升,不能判定为成功。

当结果出现不同方向时,选择路径可以直接归纳为:

  • user CPU和热点线程高:修应用、任务、查询或数据处理逻辑。
  • system、softirq或irq高:查系统调用、网络包、连接模式和I/O路径,再考虑针对性参数。
  • iowait高:查磁盘、数据库I/O和内存回收,不要优先调CPU参数。
  • steal高:核查虚拟化资源争用,虚拟机内调参通常不是根本动作。
  • 明确存在队列、描述符或连接跟踪耗尽:在记录旧值、评估内存和准备回滚的前提下,进行单项内核参数验证。
  • 没有明确资源边界证据:不要为了让告警暂时下降而批量调参,继续沿进程、请求和数据库链路寻找实际消耗来源。
目录结构
全文