VPS 负载高怎么排查:两台长跑真机的健康基线

VPS 负载高怎么排查,别一上来就拿 load 去除以核数。站得住的顺序是先看 uptime 三个数在往上走还是往回落,用 /proc/loadavg 和 ps 数清运行队列里 R 状态、D 状态各有多少任务,再翻 free 的 available,最后才决定要不要动手。要判断一个数高不高,得先见过一台长期正常跑着的机器,这些数平时长什么样。
2026-11-05 09:16,两台自有生产探测源同一批采了样。一台连跑 104 天 18:58,load 是 0.03, 0.04, 0.00;另一台连跑 230 天 17:43,load 是 0.00, 0.02, 0.05。都很闲,这次没有抓到高负载现场,本文不提供高负载实测数值。
uptime 里三个数看不明白、free 里 used 快顶到 total、ss -s 里 estab 一大串,这些确实容易让人心里发紧。这篇给的东西分三块:两台长跑机器的健康基线、Linux 官方手册对 load 的定义、一套不改配置的四步排查顺序。两台机器都是自有生产探测源,不是任何商家拿来卖的 VPS 样机,所以这里不谈配置高低,也不给选购结论。原理那几条来自手册原文和通行解释,不是这次采样测出来的结果。
想顺着长期在线机器的口径继续看,历史读数归档 里另有一套按机型整理的数据。
关键要点
- 两台自有生产探测源同为 2 核,连跑 104 天 18:58 与 230 天 17:43,uptime 三个数分别是 0.03, 0.04, 0.00 和 0.00, 0.02, 0.05,健康基线都落在极低区间。
- Linux 官方手册写明 load 统计的是运行队列 state R 加等磁盘 I/O 的 state D 任务数,不是 CPU 使用率百分比。
- /proc/loadavg 第四字段 1/344、1/474 是当前可运行调度实体数比系统现存总数,第五字段 3534024、11414 只是最近创建的进程 PID。
- used 1.5Gi / 1.8Gi、estab 89 这类看着吓人的读数,在两台机器上对应的 load 都接近 0,判据要看 available、R/D 状态和三个数的趋势。
- 本次采样两台机器都很闲,没有抓到高负载现场,本文不提供高负载实测数值。
先把两台长跑真机摆出来:健康基线长什么样
讲负载的文章,多半在教怎么救火。很少有人回答一个更基础的问题:一台跑了上百天、业务还在线的机器,uptime 那三个数平时该是多少。缺了这个参照物,拿到一个数字就只能靠猜。
两台探测源分别标清楚,别混着看
两个源必须分开写,地域、运营商、地址都不能串。cn-probe-1 是自有生产探测源,机房网络为中国广东·电信 AS4816(单线),地址 103.39.226.31。cn-probe-2 同样是自有生产探测源,机房网络为中国北京·阿里云 AS37963(BGP 多线),地址 8.140.30.240。这里写的是机器所在的网络归属,不是把它说成某家的 VPS 产品。
两台的 hostname、内核和采集时刻,原样放这里:
cn-probe-1
hostname: HNMOD
uname -a: Linux HNMOD 6.8.0-40-generic #40-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 5 10:34:03 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
date: Thu Nov 5 09:16:03 AM CST 2026
nproc: 2
cn-probe-2
hostname: iZ2ze87wqglz1tcxrwa4ebZ
uname -a: Linux iZ2ze87wqglz1tcxrwa4ebZ 3.10.0-1160.95.1.el7.x86_64 #1 SMP Mon Jul 24 13:59:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
date: Thu Nov 5 09:16:14 CST 2026
nproc: 2
cat /proc/cpuinfo | grep -c '^processor' 两台也都是 2。这点后面要反复用到:同为 2 核,是这台对照能成立的前提。内核版本差得挺远,一台 6.8.0-40-generic,一台 3.10.0-1160.95.1.el7.x86_64,这决定了后面 PSI 那项能不能读到,先记一笔。
uptime 的原始输出,一行不改:
09:16:04 up 104 days, 18:58, 1 user, load average: 0.03, 0.04, 0.00
09:16:14 up 230 days, 17:43, 0 users, load average: 0.00, 0.02, 0.05
up 104 days, 18:58 和 up 230 days, 17:43 说的是连续运行多久,业务一直在线。这类长跑机器最值钱的地方不是某个瞬间的读数,是它把正常运行时的样子画出来了。
三个数不是按大小排的,是三个时间窗
很多人第一次看 uptime,会下意识把 0.03, 0.04, 0.00 当成一组从大到小或者从小到大的排序,然后困惑于第二个数为什么比第一个大。它根本不是排序。
按 proc_loadavg(5) 手册页 的原文,前三个字段是 averaged over 1, 5, and 15 minutes,也就是 1 分钟、5 分钟、15 分钟三个时间窗上的平均值,和 uptime(1) 给的是同一组数。cn-probe-1 是 1 分钟 0.03、5 分钟 0.04、15 分钟 0.00,1 分钟略低于 5 分钟,15 分钟最低;cn-probe-2 反过来,0.00、0.02、0.05,1 分钟最低,15 分钟最高。两组形状不一样,但都贴在 0 附近,没有一组在往上冲。
读法就一条:拿 1 分钟那个数去比 5 分钟和 15 分钟。1 分钟明显高于后两个,说明压力是近几分钟才起来的;1 分钟明显低于后两个,说明前面忙过一阵、现在正在退。两台都属于「三个数咬得很紧、量级极低」,这就是健康基线的形状。至于内核里具体怎么算平均,手册只写了 averaged over 1, 5, and 15 minutes,通行解释是带衰减的滑动平均(常叫指数移动平均),越近的采样权重越大。这一句是原理说明,不是本次采样验证出来的东西。
load 到底在数什么:和 CPU 使用率不是一回事
把定义摆正,后面所有判断才不会歪。这也是 VPS 负载高怎么排查最容易走岔的一步:把 load 当成 CPU 忙不忙的百分比。
/proc/loadavg 五个字段逐列拆
cat /proc/loadavg 两台的原始输出:
0.03 0.04 0.00 1/344 3534024
0.00 0.02 0.05 1/474 11414
五个字段,一个一个对。前三个刚讲过,是 1、5、15 分钟的平均任务数。第四字段由斜杠隔开两个数,手册原文写的是:The first of these is the number of currently runnable kernel scheduling entities (processes, threads). The value after the slash is the number of kernel scheduling entities that currently exist on the system. 翻成能用的话,斜杠前是这一刻可运行的调度实体数,斜杠后是系统里现存的调度实体总数。所以 cn-probe-1 的 1/344 意思是 344 个实体里当前 1 个可运行,cn-probe-2 的 1/474 是 474 个里 1 个可运行,跟核数、跟百分比都没有换算关系。
第五字段手册写得很短:The fifth field is the PID of the process that was most recently created on the system. 就是最近一次创建的进程 PID,3534024 和 11414 是两台机器各自最近一次创建的进程 PID,数值差得远,但对判断负载没有用。这里顺手记一个容易踩的坑:ps -eo stat | wc -l 两台分别是 144 和 123(含表头行),跟第四字段斜杠后的 344、474 不是一回事,一个按进程条目数,一个按内核调度实体数,别拿来对账。
手册原文:数的是 R 状态加 D 状态
DESCRIPTION 段那句最要紧,原文照抄:The first three fields in this file are load average figures giving the number of jobs in the run queue (state R) or waiting for disk I/O (state D) averaged over 1, 5, and 15 minutes. They are the same as the load average numbers given by uptime(1) and other programs.
load 数的是运行队列里可运行的任务(state R)加上等磁盘 I/O 的任务(state D),不是 CPU 使用率百分比。 这句话得归给 Linux 官方手册,不是这两台机器测出来的。由此还能推出一条同样属于手册与通行解释范围的推论:一批进程卡在不可中断的 I/O 等待里,会把 load 顶上去,而 CPU 那边可能大片空闲。也就是说,load 高和 CPU 忙是两件事,混着看就会开错药方。
用 ps 数一遍,跟 load 对上
原理归原理,这两台机器上队列里到底有什么,用只读命令能数出来:
ps -eo stat | wc -l cn-probe-1: 144 cn-probe-2: 123
ps -eo stat | grep -c '^D' cn-probe-1: 0 cn-probe-2: 0
ps -eo stat | grep -c '^R' cn-probe-1: 1 cn-probe-2: 1
D 状态 0、R 状态 1,和三个数都贴在 0 附近完全对得上。R 那个 1 要留个余地:统计命令本身跑起来的瞬间可能被计进去,这是这类一次性计数的正常噪声,不影响结论。
ps 排序输出的前 8 行也能看出机器在干什么,原样贴 cn-probe-1:
PID PPID STAT %CPU %MEM WCHAN COMMAND
3533947 1 Ss 6.2 0.5 ep_poll systemd
3534033 2326 Ss 5.0 0.4 do_poll.constprop.0 sshd
3533943 2326 Ss 2.4 0.5 do_poll.constprop.0 sshd
1601677 1 Ssl 0.4 3.8 futex_wait_queue monitor
2124 1 Sl 0.3 13.5 futex_wait_queue anqicms
3514121 1 Sl 0.3 0.7 do_select BT-Task
784 1 Ssl 0.3 1.3 ep_poll mta-sts-daemon
945 1 Ssl 0.3 0.2 ep_poll redis-server
cn-probe-2:
PID PPID STAT %CPU %MEM WCHAN COMMAND
11377 1405 Ss 1.3 0.3 poll_schedule_timeout sshd
32646 1 Ssl 0.5 2.0 hrtimer_nanosleep AliYunDunMonito
727 1 Sl 0.3 2.1 hrtimer_nanosleep AliSecCheck
8247 616 Sl 0.3 13.0 futex_wait_queue_me dotnet
2814 1 Sl 0.2 0.4 poll_schedule_timeout BT-Task
32613 1 Ssl 0.2 0.2 hrtimer_nanosleep AliYunDun
10052 23181 S 0.1 1.5 ep_poll nginx
11671 533 Ssl 0.1 1.2 futex_wait_queue_me oneav
WCHAN 那一列全是 ep_poll、do_poll.constprop.0、futex_wait_queue、hrtimer_nanosleep 这类等待点,进程基本都在睡,没有谁在抢 CPU。还有一点必须说清楚:这里的 %CPU 是进程自启动以来的历史平均,不是此刻的瞬时 CPU 使用率。systemd 那行 6.2、sshd 那行 5.0,是长跑攒出来的均值,拿它当此刻占用 6.2% 就错了。
真要看这 6 秒窗口 CPU 忙不忙,得从 /proc/stat 前后两行算。两台的原始输出:
cn-probe-1 t1: cpu 54275077 61529 25448550 1706270567 6566520 0 2259417 0 0 0
cn-probe-1 t2: cpu 54275099 61529 25448565 1706271737 6566526 0 2259419 0 0 0
cn-probe-2 t1: cpu 34844138 2284 11722823 3903919142 18843094 0 620012 0 0 0
cn-probe-2 t2: cpu 34844151 2284 11722829 3903920340 18843096 0 620012 0 0 0
两次读取间隔 6 秒,按 100 * (Δtotal - Δ(idle+iowait)) / Δtotal 算出来的派生值是 3.21 % 和 1.559 %。小数位照原样留着,这是从两行原始输出推出来的,不是仪表盘直接读的瞬时值。cn-probe-1 的 /proc/pressure/cpu 也印证了同一件事:
some avg10=0.36 avg60=0.08 avg300=0.02 total=49384462308
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 这一行要按内核约定来读。按 kernel.org 官方文档 的说明,CPU full 在系统级没有定义,较新内核为兼容旧行为把它记为 0,所以这行的 0.00 不作判断依据,也不能拿来证明有没有 CPU 争抢。some 与 full 各字段的含义同以该文档为准,属于官方文档说明,不是这次采样测出来的结论。cn-probe-2 那个 3.10 内核不提供 PSI,cat /proc/pressure/cpu 回的是 cat: /proc/pressure/cpu: No such file or directory,io 和 memory 同样读不到,这项如实记为未取得,不补数。
健康基线加官方定义:那条判据为什么不能单独用
网上流传的是经验公式,不是手册定义
中文教程里常见一个判据:load 持续高过核数就算过载,或者把 1 分钟的 load 除以核数看商有没有过线。说法写得都很肯定,但它是经验公式,手册里没有这条。手册从头到尾只讲队列里有哪些状态的任务,不给过载线。也正因为它是经验判据,用之前得知道它的适用前提。
把两台机器摆进去看,会碰到一个绕不开的事实:它们的 load 都远低于 2 核这个分母。所以这不是「拿真机把阈值证伪了」,这两台能给的只是分母那一侧长什么样,任何关于 load 冲到多少会怎样的话,这里都不说。
能说的是另一层:既然手册定义里 load 数的是 R 加 D 的任务数,那么同一串数字底下可能藏着完全不同的两幅画面。全是 R,是 CPU 排队;掺进一批 D,是 I/O 卡住,CPU 反而可能闲着。一个只比大小的判据分不出这两种,也就不该单独拿来定「该不该处理」。再叠上没有健康基线作参照、不知道三个数在往上还是往下,单点数字能说明的东西就更少。这不是说那条经验判据全错,是说它得配上队列状态和趋势一起用。
内存看着快满了,load 却很稳
最常见的虚惊来自 free。两台的 free -h 原样贴:
total used free shared buff/cache available
Mem: 1.8Gi 1.5Gi 119Mi 17Mi 376Mi 318Mi
Swap: 1.0Gi 0B 1.0Gi
total used free shared buff/cache available
Mem: 1.7G 1.2G 85M 53M 403M 290M
Swap: 1.0G 283M 741M
cn-probe-1 的 used 1.5Gi 对 total 1.8Gi,free 只剩 119Mi,第一眼确实像要出事。可同一行 buff/cache 是 376Mi,available 是 318Mi,Swap 一点没动(0B)。used 高不等于内存不够,available 才是还拿得出来的那部分,页缓存本来就能回收。cn-probe-2 是 used 1.2G、total 1.7G、available 290M、buff/cache 403M、Swap 用了 283M,Swap 那 283M 是长跑攒下的,也不构成告警。
两台的 load 呢,0.03, 0.04, 0.00 和 0.00, 0.02, 0.05,稳得像没在干活。把 free 和 uptime 并排看,结论很朴素:内存 used 逼近 total,跟系统负载高,是两条独立的线。看到 used 就想动配置的,多半是被这一列吓的。这类判断不需要换机器,把 available、buff/cache、Swap 三项一起读完就能放下。真顺着存储接着查,两台真实服务器的磁盘空间排查 那篇用的也是这套逐列读原始输出的办法。
健康基线该盯哪几个数
综合两台的输出,一台闲着的 2 核长跑机,画像大致是这样:uptime 三个数量级极低且互相咬合;/proc/loadavg 第四字段斜杠前是 1,说明当前可运行实体就一个;ps 数 D 状态为 0、R 状态为 1;free 的 available 还有几百 Mi;/proc/stat 推出来的 CPU busy 派生值只有 3.21 % 和 1.559 %。
该盯的是这几个数之间的关系,不是某个单点。什么时候不用管:三个数都低、D 状态为 0、available 有余量、WCHAN 里全是等待点。什么时候才真该往下查:三个数里短窗的明显抬头且不肯回落、D 状态成批出现、available 被吃干净、CPU busy 派生值和 load 走势对不上。后一类现场这次没采到,所以只给判据,不给数字。
跨地域、跨运营商对照:结论只能限定着说
同一时刻两台放一张表
两台在同一批采样里,读数可以直接并排。带空格的值加了不折行处理,免得表格把 1.5Gi / 1.8Gi 这类读数拆成两截。
| 项目 | cn-probe-1 | cn-probe-2 |
|---|---|---|
| 归属 | 自有生产探测源 | 自有生产探测源 |
| 地域与线路 | 中国广东·电信 AS4816(单线) | 中国北京·阿里云 AS37963(BGP 多线) |
| 地址 | 103.39.226.31 | 8.140.30.240 |
| hostname | HNMOD | iZ2ze87wqglz1tcxrwa4ebZ |
| 内核 | 6.8.0-40-generic | 3.10.0-1160.95.1.el7.x86_64 |
| 连续运行 | 104 days, 18:58 | 230 days, 17:43 |
| nproc | 2 | 2 |
| uptime 三个数 | 0.03, 0.04, 0.00 | 0.00, 0.02, 0.05 |
| /proc/loadavg 第四字段 | 1/344 | 1/474 |
| 第五字段(最近 PID) | 3534024 | 11414 |
| ps 行数(含表头) | 144 | 123 |
| D 状态 | 0 | 0 |
| R 状态 | 1 | 1 |
| ss -s Total | 239 | 420 (kernel 501) |
| ss -s ESTAB | 6 | 89 |
| free used / total | 1.5Gi / 1.8Gi | 1.2G / 1.7G |
| free available | 318Mi | 290M |
| free buff/cache | 376Mi | 403M |
| Swap used | 0B | 283M |
| CPU busy(6 秒窗口派生值) | 3.21 % | 1.559 % |
| PSI cpu full avg10 | 0.00 | 未取得 |
判据看的是机器在干什么,不是地域或运营商
一台在广东电信单线,一台在北京阿里云 BGP 多线,地域不同、运营商不同、内核差了两代,但同为 2 核、同样长期在线,健康基线都落在极低区间。这张表能撑起的结论只有一句限定式的:判据看的是机器在干什么,不是地域或运营商。换台机器、换个时段,该看的还是 uptime 三个数的趋势、R/D 状态、available 这几项。
不能往外推的也说明白:这两台都很闲,没有高负载现场,所以表里没有任何一格能拿来当「过载线」。更谈不上推翻某条阈值,或者证明某地的机器负载更低。跨地域对照在这里的用处,是排掉一个干扰:换条线路,读数是不是就不一样。要盯的还是机器本身在跑什么。要按线路和地域翻资料,按线路和地域整理的商家资料 可以顺手对一遍,那是另一套按线路归拢的口径。
真遇到负载高,只读四步怎么查
排障意图还是得接住。下面四步全落在只读命令上,不装包、不改配置、不重启服务,这也正是两台探测源这次采集用的口径。
先看趋势,再数队列
uptime 连着跑几次,把 1、5、15 分钟三个数抄成一列,看短窗是在抬还是在落。只看一次等于抽了个快照,判断不了方向。接着 cat /proc/loadavg,读第四字段斜杠前那个数,它告诉你此刻有几个可运行实体;再用 ps -eo stat | grep -c '^D' 和 grep -c '^R' 把 D、R 分开数。D 成批出现而 CPU 派生值不高,方向是 I/O;R 多才轮到怀疑 CPU 排队。
然后查内存和连接
free -h 盯 available 和 buff/cache,别被 used 吓住。ss -s 看连接构成。cn-probe-2 那台就有个挺典型的场景:Total: 420 (kernel 501),TCP: 163 (estab 89, closed 55, orphaned 0, synrecv 0, timewait 53/0), ports 0,89 条 ESTAB 摆在眼前,第一反应容易是「连接这么多,负载肯定不低」。可同一时刻它的 load 是 0.00, 0.02, 0.05,D 状态 0,R 状态 1,CPU busy 派生值 1.559 %。cn-probe-1 那边 Total: 239、TCP: 39 (estab 6, closed 20, orphaned 1, timewait 9),estab 只有 6,load 反而还略高一点。连接数和 load 不是一条线,89 条 ESTAB 在这台机器上就是正常的长连接存量。
/proc/stat 隔几秒取两行算 CPU busy,PSI 能读就读 cat /proc/pressure/cpu 的 full 那行,读不到就像 cn-probe-2 那样记未取得,别硬凑。四步全是只读,留着原样输出比事后回忆可靠。顺带提一句,负载高和延迟高是两码事,延迟测量那篇方法论 讲的是另一套指标。网卡侧另有 VPS MTU 排查那篇 可对照。
一页速查
| 看到的现象 | 先跑哪条 | 怎么判 |
|---|---|---|
| uptime 三个数不齐、不知道算不算高 | uptime 连读几次 |
看短窗相对长窗是抬还是落,别盯单点 |
| 想确认是不是 CPU 在排队 | cat /proc/loadavg + ps -eo stat |
第四字段斜杠前小、D 为 0、R 为 1 就是闲 |
| free 里 used 快顶到 total | free -h |
看 available 与 buff/cache,别急着动配置 |
| ss 里 estab 一大串 | ss -s + uptime |
连接数不直接进 load 的计算 |
| ps 的 %CPU 看着挺高 | 结合进程启动时长看 | 那是自启动以来的历史平均,不是瞬时值 |
| 想核 CPU 忙不忙 | /proc/stat 隔几秒两行 |
按派生式算,或读 PSI 的 full 行 |
| 手册怎么定义 load | 查 proc_loadavg(5) | 数的是 R 加 D 的任务,不是 CPU 百分比 |
常见问题
load average 多少算正常?
没有脱离机器的统一数字。这两台同为 2 核、连跑 104 天 18:58 与 230 天 17:43 的自有生产探测源,三个数是 0.03, 0.04, 0.00 和 0.00, 0.02, 0.05,可以当一份健康基线用。真要判断某台机器,拿它自己闲时的读数比,再叠上 D 状态、available 和三个数的趋势,比套固定阈值靠谱。本次采样两台机器都很闲,没有抓到高负载现场,本文不提供高负载实测数值。
uptime 三个数值分别代表什么?
1 分钟、5 分钟、15 分钟三个时间窗上的平均任务数,不是按大小排序,也不是瞬时值。按手册原文,它们和 cat /proc/loadavg 前三个字段是同一组数。cn-probe-1 是 0.03, 0.04, 0.00,1 分钟略低于 5 分钟;cn-probe-2 是 0.00, 0.02, 0.05,1 分钟最低、15 分钟最高。形状不同,量级都很低。
Linux 负载和 CPU 使用率有什么区别?
load 数的是运行队列里 state R 加等磁盘 I/O 的 state D 任务数,CPU 使用率看的是时间片花在哪,两者不是同一个量。手册与通行解释里,D 状态任务成批卡住时 load 会上去而 CPU 可能大片空闲。这次两台的 CPU busy 派生值是 3.21 % 和 1.559 %,PSI cpu 的 full avg10=0.00 按内核约定只作原始记录,不作 CPU 争抢与否的判断依据,也不能拿来反推 load。
/proc/loadavg 怎么看后面两个字段?
第四字段是斜杠隔开的两个数,前面是当前可运行的调度实体数,后面是系统现存的调度实体总数,两台是 1/344 和 1/474。第五字段是最近创建的进程 PID,3534024 和 11414,跟负载判断无关。别把它和 ps -eo stat | wc -l 的 144、123 混成对账关系,两者统计口径不同。原文见 Linux man-pages 的 proc_loadavg(5)。
4 核 VPS load 到 8 要不要紧?
这是搜索里很常见的问法,问法里的两个数字不是这两台机器的读数,这次也没有抓到那样的现场,所以不给实测数值。按手册定义能说的是:那个数只是 R 加 D 任务的平均值,得先看里头 D 状态占多少、三个数在不在往上走、free 的 available 还剩多少、ps 的 WCHAN 停在什么等待点。光比它和核数的大小,判不出该不该处理。
小结:先见过健康基线,再谈阈值
把两台长跑真机摊开,得到的不是一条新阈值,是一个参照物。同为 2 核、连跑 104 天 18:58 与 230 天 17:43、地域和运营商都不同,uptime 三个数都贴在 0 附近,D 状态 0,available 有余量,CPU busy 派生值 3.21 % 和 1.559 %。手册那边补上了另一半:load 数的是 R 加 D 的任务,不是 CPU 百分比。两半合起来,才明白「超过核数就过载」这类经验判据为什么不能单独用。
VPS 负载高怎么排查,落到动作上就四步:连读 uptime 看趋势,用 /proc/loadavg 和 ps 数 R/D,翻 free 的 available,扫一遍 ss -s。四步都只读,输出留原样。下次再看到 used 快满或者 estab 一大串,先把这台机器闲时的样子翻出来对一对,多半就是一场虚惊。把这几条命令存成自己的检查单,比挑配置实在得多。站里的 在售套餐与优惠汇总 另收着一份整理好的清单,备查。
