news 2026/10/18 13:07:20

loadavg高但CPU低?D状态与PSI压力指标排查实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
loadavg高但CPU低?D状态与PSI压力指标排查实战

凌晨 2 点 15 分,监控平台弹出告警:某业务实例的 1 分钟 loadavg 冲到 180,而 5 分钟和 15 分钟平均值还不到 10。切到服务器上看一眼,CPU 总体才 30% 出头,磁盘 IO 也只有零星几个百分点。第一反应是监控抽风;第二反应是——熟悉的味道,这又是一次 loadavg 和 CPU 使用率“对不上”的经典现场。

这篇文章是这次 loadavg 异常的完整排查记录,也顺带整理成一套可以反复套用的排错框架。内容涉及 loadavg 的统计机制、D 状态任务的判别、PSI 压力指标的使用、几类高频异常的复盘,以及我在实际操作中踩过的坑。无论你是刚接手服务器运维的新手,还是需要应对生产环境告警的开发者,这套思路都可以直接抄作业,命令也是现成的。

1. 先搞懂 loadavg 到底在统计什么

1.1 三个数字是“任务数”,不是 CPU 百分比

先说一个很多人都绕晕过的点:/proc/loadavg 里的三个数,分别代表最近 1 分钟、5 分钟、15 分钟里,处于“可运行”或“不可中断睡眠”状态的任务平均数量。它统计的是任务数量,不是 CPU 占比,量纲是“个”。只是因为一个 CPU 核同一时刻最多运行一个任务,所以当 loadavg 数值等于 CPU 核数时,可以近似理解成“每个核都在忙”。

具体到内核实现,统计的是两类任务的和:

  • TASK_RUNNING:正在 CPU 上执行、或者排入运行队列等待调度的任务。
  • TASK_UNINTERRUPTIBLE,也就是常说的 D 状态:不可中断睡眠的任务,常见于等待磁盘 IO、等待网络文件系统响应、等待内核态锁。这类任务即使睡眠,也不能被信号打断。

所以一句话理解:loadavg 上涨,本质上是“运行队列上排队的任务变多了”,或者“阻塞在核心资源上的任务变多了”。前者对应 CPU 过载,后者对应 IO、锁或者设备故障。

1.2 移动平均是怎么算出来的

搞明白计算机制,你就能解释为什么告警里三个数字经常“脱节”。内核不是实时算这三个数,而是每隔 5 秒采样一次,然后对采样结果做指数加权移动平均。

简化公式就是:新 load = 旧 load × 衰减系数 + 当前活动任务数 ×(1 - 衰减系数)。衰减系数决定了历史数据对当前值的“拖拽”程度:1 分钟平均衰减快、反应灵敏,15 分钟平均衰减慢、表现平滑。所以当你看到 1 分钟值瞬间拉得很高、15 分钟值纹丝不动时,说明这是一个刚刚发生的突发现象;反过来如果三个数一起高,说明系统已经持续高压了一段时间。

这个机制在排查时非常有用。我习惯把三个数连起来读:1 分钟和 5 分钟差距大,说明是瞬时冲击;5 分钟和 15 分钟都高,说明问题已经潜伏很久,要尽快扩大排查面,不能只盯着刚发生的表象。

1.3 为什么 D 状态任务会被计入 loadavg

这是 Linux 和很多其他操作系统最大的差异点,也是最容易踩坑的地方。Linux 之所以把不可中断睡眠任务也算进 loadavg,是因为这类任务占用了宝贵的资源——比如磁盘队列里的 IO 请求、内核锁、文件系统事务——这些资源不释放,后面的任务只能一直等,所以账必须记在前面的任务头上。

结果就是:loadavg 高不一定是因为 CPU 跑了太多任务,也可能是一块磁盘挂了、某个文件系统卡住、网络存储失联,导致大量任务堵在不可中断的等待里。这类问题的典型特征就是 loadavg 很高,CPU 却大量空闲。

1.4 常见误区:loadavg 高不等于 CPU 忙

既然 loadavg 统计的是任务排队数量,那么“loadavg 高就必须加 CPU 资源”这个惯性思维就是错的。遇到过不少同事看到 loadavg 超过核数就急着扩容,结果问题根本不在 CPU 上,扩容之后 D 状态任务原封不动,负载照样高得离谱。

这里有一个判断口诀可以背下来:r 队列长、CPU 繁忙 → 计算型问题;b 队列长、CPU 空闲 → IO/阻塞型问题;两个都高 → 混合型或者次生灾害。后面的内容基本都围绕这个口诀展开。

2. 异常表象速判:拿到告警后先回答三个问题

2.1 第一问:r 和 b 的分布如何

vmstat 输出的前两列是 r(running,正在运行或等待 CPU 的进程数)和 b(blocked,不可中断睡眠的进程数)。这两个数字的对比直接决定排查方向:

  • r 远大于 CPU 核数,b 几乎为 0:CPU 计算资源不足,常见于突发计算任务、定时任务集中触发。
  • b 明显大于 0,甚至几十上百,而 CPU 大多处于 idle:IO、锁或者设备层阻塞。
  • r 和 b 都高:CPU 和 IO 同时出问题,也可能任务已经被 IO 堵住但还在抢占 CPU 反复重试。

这里建议多采样几次,命令写清楚是 vmstat 1 10,持续 10 秒。单次采样可能只是瞬时值,我经历过一次典型误判:单看一次 vmstat 发现 r=200,断定是 CPU 问题,结果连续采样后发现 r 在持续下降、b 在上升,实际是磁盘故障引发的连锁反应,方向完全相反。

2.2 第二问:CPU、IO、内存三个维度谁在承压

vmstat 里还有几列关键数字要一起看:

  • us + sy 接近 100%:以计算为主,r 队列自然长。
  • wa 持续偏高:IO 阻塞为主,b 列大概率也有值。
  • si、so 不为 0:内存回收和换页压力,可能伴随 kswapd 内核线程导致负载波动。

除了 vmstat,强烈建议看 /proc/pressure 下的 PSI 指标。PSI 是内核提供的压力数据源,能直接告诉你 CPU、内存、IO 分别对任务造成了多长时间的阻塞。比如 /proc/pressure/io 的 some 列表示至少有一个任务被 IO 阻塞的时间比例,full 列表示所有任务都被 IO 阻塞的时间比例。

当 full 长期不为 0 时,IO 已经是系统性瓶颈,这时候排查方向几乎可以拍板。PSI 比“loadavg 高 + CPU 低”这种间接推断要直接得多,后面我会专门讲监控怎么用。

2.3 第三问:谁是嫌疑进程,阻塞在哪

方向定下来,就要锁定具体进程。最常用的一条命令:

ps -eo pid,ppid,stat,wchan:28,comm | awk '$3 ~ /D/'

只列出 D 状态进程。wchan 这一列是进程当前阻塞在内核的哪个函数上,它基本能告诉你“卡在哪类资源里”。举几个实际例子:如果 wchan 大量出现在文件系统日志提交相关的函数上,大概率是磁盘 IO 故障或者日志写盘卡住;如果出现在网络文件系统的 RPC 等待函数上,那就是远端存储挂起;如果出现在内存回收相关路径上,就得查内存水位和 page allocation。

有了进程列表和 wchan,接下来的动作就是顺着这条线索去查对应资源的状态。下面那节我把它整理成一套从告警到定位的完整流程。

3. 一份可直接照做的排查流程

3.1 现场信息采集:先把证据固定下来

不要在系统缓过来之后才回忆“当时发生了什么”。我的习惯是,任何人接到 loadavg 告警,第一时间把下面这几条命令的结果存成文件:

uptime cat /proc/loadavg vmstat 1 5 ps -eo pid,ppid,stat,wchan:28,comm --sort=-pcpu | head -n 30

如果内核支持,再加抓三个压力指标:

cat /proc/pressure/cpu cat /proc/pressure/io cat /proc/pressure/memory

这些加起来 30 秒内能拿到,却能在事后复盘时完整还原现场。尤其是那些几分钟后自动恢复的“幽灵故障”,没有现场快照,后面讨论起来全是猜。这算是我做运维这么久,最想强调的一个习惯:告警处理第一步永远是固定证据,而不是急着动刀。

3.2 D 状态任务定位:ps 的两条关键命令

第一步永远先分清 r 和 b。如果 b 有值,跑:

ps -eo pid,stat,wchan:28,comm | grep '\<D\>'

然后重点观察这些 D 状态进程的数量是涨还是跌。数量持续上涨,说明阻塞点在快速积压,这是故障现场,处置优先级要拉高;数量上下波动,可能是周期性的短时抖动,可以先观察。数量趋势比数量本身更能反映问题的紧迫程度。

如果 r 高而 b 几乎没有,跑:

top -H -b -n 1 | head -n 50

注意按线程视角看,而不是只看进程。多线程应用的负载往往藏在某个线程池里,进程维度的 CPU 使用率会把问题抹平,必须切到线程维度才能看到谁在真正消耗 CPU。

3.3 顺着 wchan 追根因:一条典型的追查链

wchan 是线索,但怎么从线索走到根因,这个环节比较考验经验。我拆解一条我在实践中走通过的链路:

  1. 现象:loadavg 从 5 涨到 60,CPU 使用率只有 20%,15 分钟平均值同步上涨。
  2. vmstat 显示 b=40,wa 达到 60% 以上,判断 IO 阻塞。
  3. ps 发现十几个进程处于 D 状态,wchan 指向块设备相关的等待函数。
  4. iostat -x 1 查看磁盘,发现某块盘的 %util 到 99% 以上。这里不能马上断定磁盘坏了——util 高可能是因为请求大量堆积,也可能是磁盘本身响应延迟高。
  5. 继续查 /proc/diskstats,比较 await 和 avgqu-sz。当 await 从零点几毫秒涨到几百毫秒,avgqu-sz 涨到几十,基本可以断定磁盘服务能力出了问题。
  6. 再把范围缩小到访问这块盘的进程,跟业务侧确认是否有批量扫描、备份任务同时触发。排除业务大动作后,就需要考虑硬件层面的故障,联系设备侧介入。

这个链条的核心思路是“顺着 wchan 找资源,顺着资源找进程,顺着进程找业务动作”。每一步都有对应的命令和证据支撑,不做没有根据的猜测。

3.4 内核与系统日志里找佐证

很多 D 状态阻塞并不是永久性的,而是“卡到超时才报错”。内核的 hung task 检测机制会在任务进入不可中断睡眠超过 120 秒(默认阈值)时,把这个任务打印到内核日志里,内容包括任务名称、阻塞的内核栈以及当时的任务列表快照。

dmesg -T | grep -i "hung task"

如果看到类似 “blocked for more than 120 seconds” 的条目,它后面跟着的内核栈非常关键,基本把根因写在了脸上。我遇到过的案例里,这条日志一出来,排查方向就锁定到对应的驱动层或者文件系统层了,省去大量试错。

另外,如果系统日志里夹杂着文件系统或设备层的报错,比如 IO 错误、请求超时重试之类的记录,优先级最高的动作是先确认物理设备状态,因为设备几乎已经不可用,用户态做什么尝试意义都不大。

3.5 处置策略与恢复验证

处置要分场景,不是所有 D 状态都值得立刻动手:

  • 短时抖动,比如批量任务导致的 IO 排队,业务容忍度允许的情况下可以先观察,同时拉长监控粒度。
  • IO 设备故障,优先切路径、摘流量,而不是反复重试。切忌对 D 状态进程反复发 kill,后面我会解释为什么完全没用。
  • 问题可复现,尽量先保留现场,把快照完整抓下来再处置,为的是事后能复盘。

恢复验证不能只看 loadavg 降下来。正确姿势是连续观察 15 分钟以上的三个 loadavg 数值,同时确认 b 回落到基线水平、PSI 的 full 值归零。因为 1 分钟平均值降得快,15 分钟平均值滞后明显,单看一两个采样点很容易误判“已经好了”。

4. 四类典型 loadavg 异常复盘

4.1 磁盘 IO 卡死引发的 D 状态堆积

这是最常见的一类。某台数据库实例某天下午 loadavg 突然从 8 冲到 120,CPU 不到 20%,业务接口全面超时。现场采集看到 b=60,iostat 显示数据盘 %util 满、await 超过 500ms,dmesg 里有设备层的超时重试日志。

处理结果是磁盘控制器在反复重置,属于硬件层故障。后续操作分三块:切换存储路径、把业务流量摘掉、等设备完成切换后再恢复。这次复盘里最有价值的经验是“不要因为 loadavg 高就重启应用”。重启只是杀掉了表象,IO 问题不解决,重启之后同样的 D 状态会立刻重新堆积,而且重启间隙可能导致数据不一致。

4.2 短任务风暴把 loadavg 冲高

另一种看起来更“诡异”的情况:loadavg 瞬间飙高,但 top 里根本看不到 CPU 占用高的长任务。这是短生命周期任务的典型特征——大量任务每隔几十毫秒创建、运行、退出,它们在 top 的采样窗口里来来往往,你根本看不全。

排查这类问题需要看调度器统计:

pidstat -w 1

pidstat 的上下文切换统计会显示每秒 cswch/s 和 nvcswch/s,数值异常大说明系统里有高频创建和切换任务的进程。再结合业务侧的任务调度频次,比如定时任务集中触发、消息积压导致批量消费协程爆发,就能锁定是哪个业务模块了。

这类问题的解法不在内核参数,而在业务侧:削峰、限流、把瞬时任务分散到更长的时间窗口。调内核参数去硬扛短任务风暴,往往事倍功半,这是我试过之后才明白的。

4.3 网络文件系统挂起导致的“假高负载”

曾经有位同事排查一个 loadavg 高但本地磁盘完全正常的“玄案”。后来发现根源是一个网络文件系统挂载点——远端存储网络抖动,导致一堆进程在等待 RPC 响应,全部进入 D 状态,本地磁盘毫无压力。

处理方式是调整挂载参数,比如把超时和重试配置改成符合业务特性的数值,并增加挂载超时保护。但这里要强调一个边界:能调超时不等于建议调成无脑自动恢复。对于有严格一致性要求的场景,宁可让它阻塞也不能静默返回错误,配置选择必须跟业务形态匹配,否则数据出错比负载告警严重得多。

4.4 内存回收抖动引发的系统性波动

最后一个类型容易被忽略:内存压力间接推高 loadavg。当内存不足时,内核会启动内存回收,kswapd 和直接回收路径都会消耗 CPU,同时回收过程等待页面写回也可能引入 D 状态任务,结果是 loadavg、CPU、IO 三个指标同时波动。

判断方法是查内存水位和回收指标:

cat /proc/vmstat | grep -E "pgsteal|pgscan|kswapd_steal" free -g

如果页回收速率和 swap 使用量同步上升,说明这是一场由内存水位引发的次生灾害。解法重点是给应用配置合理的内存上限,而不是盲目加大内存——很多时候问题本质是应用缓存无界增长,加多少内存都不够。

5. 常用工具与参数速查

5.1 排错命令速查表

目的命令关键关注点
快速总览vmstat 1 5r、b、wa、si/so
看 D 状态进程ps -eo pid,stat,wchan,commwchan 列定位阻塞函数
看 CPU 线程占用top -H -b -n 1线程维度,而非进程维度
看磁盘延迟iostat -x 1await、avgqu-sz、%util
看上下文切换pidstat -w 1cswch/s、nvcswch/s 异常大
看内核栈dmesg -T | grep -i "hung task"120 秒超时任务的调用栈
看压力指标cat /proc/pressure/iosome、full 两列
看内存回收cat /proc/vmstatpgsteal、pgscan、kswapd_steal

这张表基本覆盖了从“收到告警”到“定位根因”的全过程,我处理过的绝大多数 loadavg 案件都靠这些命令收尾。

5.2 为什么 D 状态进程 kill 不掉

这是排查时最常被问的问题。D 状态进程处在不可中断的内核等待路径上,信号处理本身也被阻塞,你 kill 的信号确实发出去了,但进程根本没有机会去处理,自然不会退出。所以不要反复 kill -9 一个 D 状态进程,这是纯属浪费时间的操作。

正确的思路是解决让进程阻塞的底层资源:设备恢复、文件系统恢复、网络链路恢复之后,进程会自己醒来并继续执行。如果实在等不到,且业务无法恢复,最后的手段往往不是杀进程而是重启系统,但在重启前一定要权衡数据一致性和业务影响面。

5.3 监控告警的正确打开方式

给 loadavg 设一个固定阈值,比如“超过核数就告警”,是很初级的玩法,误报率和漏报率都高。建议的做法分几层:

  • 基线对比:按实例维度保存历史 loadavg 分布,异常判定不用“超过某个数”,而是“明显偏离同时段的正常基线”。
  • 多维联动:把 loadavg 和 CPU、IO、内存压力数据做关联,告警时直接标注属于计算型还是阻塞型,值班人不用从零开始分析。
  • 引入 PSI:把 /proc/pressure 里的 some 和 full 纳入监控面板。这样告警能更早触发,而且根因方向的判断在监控端就自动完成了一半。

我在实际使用中发现,PSI 对“loadavg 高但 CPU 低”这类告警的降噪效果最明显,很多以前需要人工判断的场景,看 PSI 面板一眼就能定性。

5.4 可调整的内核参数边界

不是所有场景都建议动内核参数。以下几项是在实践中确实有效果的:

  • kernel.hung_task_timeout_secs:调整任务超时打印的阈值,可以在故障早期获得更及时的日志输出。
  • vm.swappiness:影响内存回收倾向,间接缓解内存压力类的负载波动。
  • 块设备队列深度参数:需要根据设备类型和业务 IO 模型谨慎调整,盲目调大可能让延迟恶化。

但一定得明白:参数只是缓解症状的表现形式,解决不了业务模型和硬件层面的根因。把内核参数当成故障根源的解法,是我见过最多绕弯路的操作,没有之一。

说句实在话,loadavg 这个指标被讨论了很多年,但真正让人头疼的从来不是它的算法,而是它背后五花八门的现实原因。我个人的体会是:把它当成一个“信号灯”而不是“温度计”——它只能告诉你系统出问题了,不能告诉你问题是什么。排查那种 CPU 空转但 loadavg 爆炸的问题,最幸运的时刻不是恢复业务的那一刻,而是凭着一份现场快照,在复盘中一步步还原出真相的时刻。

所以每次接到告警,先稳住,手里备好命令,按框架一步步来,大多数案子的走向都会变得清晰。最后再分享一个小习惯:在监控平台上把 /proc/loadavg 和 /proc/pressure 的数据一起存够 90 天,等真要追根因的时候,这些历史数据往往比告警文本有价值得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 13:05:59

GRU英文诗歌生成实战:原理、PyTorch实现与调优

开题&#xff1a;为什么我用GRU做英文诗歌生成&#xff0c;而不是直接用LSTM或Transformer前段时候帮一个学弟把毕设课题定在了英文诗歌生成上&#xff0c;模型框架选了GRU。这个方向听起来很文艺&#xff0c;但本质上是典型的时间序列生成任务&#xff0c;属于深度学习在自然语…

作者头像 李华
网站建设 2026/10/18 13:05:57

Python与TensorFlow实现卫星遥感图像识别系统全流程解析

卫星遥感图像识别&#xff0c;听起来好像离普通开发者很远&#xff0c;但这两年无论是耕地监测、水体提取、城市违建排查&#xff0c;还是救灾时的快速评估&#xff0c;都离不开这项技术。我刚接触这个方向时&#xff0c;以为就是把普通的图像分类搬到卫星图上&#xff0c;真做…

作者头像 李华
网站建设 2026/10/18 13:05:55

TensorFlow遥感图像识别实战:土地覆盖分类系统开发全流程

先说说我做这套系统的初衷。卫星遥感影像这几年已经不再是少数专业单位的专属资源&#xff0c;公开的数据源越来越多&#xff0c;个人开发者和中小团队都能拿到覆盖范围不小的高分辨率影像。但数据到手只是第一步&#xff0c;真正的难点在于把影像变成可用的业务信息&#xff1…

作者头像 李华
网站建设 2026/10/18 13:05:28

Java实现PAdES-LT电子签章:PDFBox+SM2/RSA合规签名实战

简介&#xff1a;本资源是一份基于Spring Boot实现Java电子签章功能的轻量级开发模板&#xff0c;面向Java后端开发者及企业级电子合同系统建设者&#xff0c;解决PDF合同自动化签署、数字签名嵌入与法律效力保障等核心问题。压缩包为ZIP格式&#xff0c;共72KB&#xff0c;虽未…

作者头像 李华
网站建设 2026/10/18 13:04:49

WebPlotDigitizer:从图表截图到数据提取的完整坐标校准与取数指南

简介&#xff1a;WebPlotDigitizer 是一款基于 HTML5 的开源在线工具&#xff0c;主要面向科研人员、工程技术人员与数据爱好者&#xff0c;用于从 XY 曲线图、极坐标图、三元图和地图等图像中快速提取数值数据&#xff0c;免去手工读数的繁琐流程。资源包共 247 个文件&#x…

作者头像 李华
网站建设 2026/10/18 13:04:18

DGX Spark 部署 SD3.5 全流程:从权重到 ComfyUI 实战指南

把话说在前头&#xff1a;NVIDIA DGX Spark 这台机器和 Stable Diffusion 3.5 的组合&#xff0c;属于那种“听起来就很有搞头、实际上也真有搞头”的本地图像生成方案。但如果你以为插上电源、装个 ComfyUI、下载一个大模型文件就能出图&#xff0c;那大概率会被三个文本编码器…

作者头像 李华