SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

VPS CPU steal time 与邻居噪声怎么判断

了解 VPS 的 CPU steal time:读取 vmstat 的 st 列,区分自身过载与邻居争用,并注意 VMware、Hyper-V 客户机可能始终显示 0 的版本与平台陷阱。

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 7, 2026.

CPU steal time 的实际含义

CPU steal time 表示:虚拟 CPU 已准备好运行且无需等待,但虚拟机管理程序将物理核心分配给了另一个 guest 的那段时间占比。任务已经排队,但物理核心被分配到了其他位置。Linux 会单独统计这些周期,并将其报告为 st。通过该指标,可以区分“我的服务器很忙”和“我的服务器正在等待调度”。

这正是该计数器存在的原因。进程在 CPU 上实际运行的时间会报告为 us(用户态)或 sy(系统态)。任务因存储操作而阻塞的时间会报告为 wa(I/O wait)。如果 vCPU(虚拟 CPU)处于可运行状态,位于运行队列中,没有未完成的 I/O,但仍未执行,则会报告为 st。服务器内部的任何操作都无法清除这种状态,因为调度决策是在下一层的宿主机上完成的。

这直接源于 VPS 如何共享一台物理机。通常原因是邻居 guest:同一节点上的另一个 guest 负载很高,因此宿主机需要在多个 guest 之间分配物理核心。还有一个容易被忽略的原因。许多提供商会将共享 vCPU 限制为物理核心的一部分;在一些虚拟机管理程序中,这个强制执行的限制会在 guest 内部计入 steal time。因此,较高的 st 读数说明物理核心没有分配给你,但不一定能说明是谁占用了它。

steal 数值的来源

内核本身无法测量 steal,因为它看不到宿主机。该数值由虚拟机监控程序提供。在 KVM 中,宿主机会将每个 vCPU 的计数器写入与客户机共享的页面;当内核启用 CONFIG_PARAVIRT_TIME_ACCOUNTING 构建时,客户机会累加这些计数器。所有发行版内核都启用了该功能。Xen 通过其 runstate 区域报告相同的数据。该总计只会在一个位置进入用户空间:

head -1 /proc/stat

该 cpu 行包含 10 个计数器,单位是自启动以来的 USER_HZ tick,顺序如下:user、nice、system、idle、iowait、irq、softirq、steal、guest、guest_nice。steal 是标签后的第 8 个值。下面的每个工具,包括 vmstat、top、mpstat 以及任何 Prometheus exporter,都会读取同一个字段,并根据两次采样计算百分比。

其中一个后果比其他问题更重要。如果虚拟机监控程序从不导出该计数器,该字段就会永久保持为 0,所有基于它的工具都会报告平稳的 0.0,即使宿主机已经过载。KVM 和 Xen 会导出该计数器。在其他平台上,包括 VMware 和 Hyper-V,是否能看到 steal 取决于宿主机导出的数据以及客户机内核的支持情况。因此,那里持续为 0 本身不能证明没有资源争用。确认平台后,再判断 0 是否可信:

systemd-detect-virt

该命令会输出平台名称,例如 kvm、xen、vmware 或 microsoft;在裸机上则输出 none。在容器内,它会改为报告运行时,例如 lxc、docker 或 podman。这只能说明容器的运行环境,不能说明底层机器。在 kvm 上,0 表明宿主机确实没有占用你的 CPU 时间。在从不填充该字段的平台上,0 完全不能作为证据;必须通过实际运行任务时的耗时来判断资源争用。

如何检查 VPS 上的 CPU steal time?

vmstat 来自 procps 软件包。几乎所有 Ubuntu 和 Debian VPS 镜像都已包含该软件包,但部分精简容器镜像中没有,因此在依赖它之前先安装。

sudo apt-get update
sudo apt-get install -y procps
vmstat --version
vmstat 1 5

vmstat --version 会输出类似 vmstat from procps-ng 4.0.4 的一行。如果能输出该内容,说明工具已安装,并且读取的是真实内核计数器。随后,vmstat 1 5 会输出 5 份报告:第 1 份是自启动以来的平均值,后 4 份是每隔 1 秒采集的样本。

procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st gu
 1  0      0 3216484  98304 1284360    0    0     4    18   62  110  3  1 96  0  0  0
 2  0      0 3216232  98304 1284360    0    0     0     0  248  431  6  2 84  0  8  0

在右侧的 cpu 区块中找到 st 列。当前版本的 procps-ng 会在该列后输出一个用于 KVM guest time 的 gu 列,因此 st 是从右侧数第 2 列,而不是最后一列。请按列标题读取该列,因为不同版本中列的位置可能发生变化。

以下两个习惯有助于确保读数准确。第 1 行数据是自启动以来的平均值,因此应忽略该行,读取后面的行。单个样本也不能作为测量结果,因为 steal time 可能集中出现:运行 vmstat 1 61。该命令会在自启动以来的那一行之后,采集 60 个每隔 1 秒的样本。观察完整 1 分钟后,再得出结论。

top 会在其 %Cpu(s) 汇总行中报告相同的数值,字段标记为 st:

%Cpu(s):  6.2 us,  2.1 sy,  0.0 ni, 83.9 id,  0.0 wa,  0.0 hi,  0.3 si,  7.5 st

如需查看每个 CPU 的详细信息,添加 sysstat:

sudo apt-get install -y sysstat
mpstat -P ALL 1 5

mpstat 会为每个 CPU 输出一行,其中包含 %steal 列。该列可以显示所有 vCPU 是否都受到影响,还是只有一个 vCPU 受到影响。要保留支持工单所需的历史记录,不要只在屏幕上查看样本:

date -u | tee -a ~/steal.log
mpstat -P ALL 1 5 | tee -a ~/steal.log

在你怀疑出现问题的时间段内,通过 cron 运行该命令。这样,文件中就会保存确切的 10 分钟记录,而不只是告诉服务提供商“昨晚感觉很慢”。

抢占时间数值表示什么?

  • 稳定的 0.0。 系统状态正常,或者平台根本不报告 steal。庆祝之前,先使用 systemd-detect-virt 确认。
  • 持续数秒、达到几个百分点的尖峰。 在任何共享节点上都属正常。邻居的构建任务启动了,或者宿主机正在运行备份。
  • 共享套餐中持续保持 1 到 5%。 属于预期情况。共享 CPU 的成本优势就体现在这里。
  • 持续保持 5 到 10%。 已经可以测量到性能下降。开始记录证据,并比较连续几天的相同时段。
  • 每次持续数小时、超过 10%。 可能是该节点相对于你的工作负载超额分配,也可能是系统正在执行套餐的 CPU 限制;部分提供商会将该限制报告为 steal。这种情况足以提交支持工单或迁移服务。

应将这些区间作为判断参考,而不是规格标准,因为没有提供商会为共享套餐发布 steal 保证。应结合你的实际工作负载进行评估。一个夜间批处理任务即使承受 15% 的 steal 也可能不会被察觉。延迟敏感型服务的 p99 指标会更早反映问题,平均值可能还没有明显异常。因此,交易机器人等延迟敏感型工作负载应运行在专用 CPU 核心上。

偷取时间会造成多少成本?

计算很简单。如果 CPU 时间中有 s 被占用,需要固定 CPU 时间的任务在实际时钟时间上就会变为原来的 1 / (1 - s) 倍。对于需要 60 秒 CPU 时间的任务:

图表Wall clock time for a job needing 60 seconds of CPU
此图表背后的数据
[
  {
    "steal_percent": 0,
    "wall_clock_seconds": "60.0"
  },
  {
    "steal_percent": 3,
    "wall_clock_seconds": "61.9"
  },
  {
    "steal_percent": 8,
    "wall_clock_seconds": "65.2"
  },
  {
    "steal_percent": 15,
    "wall_clock_seconds": "70.6"
  },
  {
    "steal_percent": 25,
    "wall_clock_seconds": "80.0"
  },
  {
    "steal_percent": 40,
    "wall_clock_seconds": "100.0"
  }
]

在 3% 的情况下,这是普通共享型套餐中的常见读数,该任务需要 61.9 秒,而不是 60.0 秒。通常不会有人因此提交工单。在 8% 时,需要 65.2 秒。在 40% 时,同一任务需要 100.0 秒,原本可以持续清空的队列则会开始增长。

这些是计算值,不是测量值。该模型假设只有一个可运行线程,并且偷取时间在整个时间间隔内均匀分布。实际服务通常会感觉比曲线显示的情况更糟,因为被偷取的时间片可能发生在请求处理中间,等待该请求的所有操作随后还要再次承担这段延迟。要获得自己的数据而不是使用公式,请在低峰时段和高峰时段分别对 VPS 进行基准测试,并记录两个时间窗口的 st。

这是 steal,还是其他问题?

Steal 很容易与其他症状混淆。请在同一行 vmstat 中结合查看这些计数器。

  • st 较高,而 r 和 us 保持较低:主机没有向你提供 CPU 核心时间。这就是 steal。
  • r 明显高于你的 vCPU 数量,同时 us 较高、st 接近 0:你运行的工作量超过了自有 CPU 的处理能力。将 r 与 nproc 的输出进行比较。这是你自己的超额订阅,不是邻居实例造成的。
  • wa 较高,而 st 接近 0:任务被存储操作阻塞。这是另一类问题,需要采用不同的修复方法。
  • 负载平均值较高,而 st 和 us 都较低:负载值还会统计不可中断任务,因此这通常表示设备卡住或网络挂载无响应,而不是 CPU 问题。

突发型计划需要单独说明。这类计划会在实例空闲时累积信用额度,在实例繁忙时消耗信用额度;额度用尽后,云服务提供商会将实例限制在基准速率。某些平台会将这种限速报告为 steal。其他平台不会在实例内部显示该限速,你只会获得更少的每秒 CPU 周期。在判断是否由邻居实例造成问题之前,请先阅读计划说明。

为什么容器报告没有 steal time

Steal 是虚拟机的属性,不是其中运行的容器的属性。您在自己的 VPS 上运行的 Docker 容器会共享主机的 /proc,因此在容器内读取的 st 值就是 VPS 的 steal,这正是您需要的结果。作为 VPS 销售的基于容器的虚拟化则不同。启用 lxcfs 后,容器内的 /proc/stat 会根据 cgroup 统计信息合成,因此 steal 按设计始终为 0。只从容器内部抓取指标的监控系统,可能显示一个平稳且毫无异常的 0,而底层物理机实际上已经资源不足。

在容器内,具有相同含义的计数器是 CPU 配额限流。在 cgroup v2 中:

cat /sys/fs/cgroup/cpu.stat

nr_throttled 统计该组触发 CPU 配额的强制执行周期数,throttled_usec 统计该组被冻结的总时间。nr_throttled 持续上升表示您的进程处于可运行状态,但没有获得运行机会;这与 steal 的体验相同,但原因是您自行设置了限制。请先检查您自己的限制,再判断是否应归咎于主机。尤其是在 compose 文件中设置了 CPU 限制,并且您 在 VPS 上使用 Docker 运行服务时,更应如此。分层虚拟化会增加一个额外的时间损耗来源,因为 VPS 内的虚拟机既要承担 VPS 的 steal,还要承担自身的调度延迟。如果您 在 VPS 上运行嵌套虚拟化,请注意这一点。

持续 steal 时该怎么办

来宾系统内部的任何设置都无法修复 steal,因为作出调度决策的调度器运行在来宾系统之外。升级内核也不会改变这一点:Linux kernel 7.2 中新增的缓存感知调度会在实际分配给你的 CPU 核心之间重新安排任务,但无法恢复已被邻居虚拟机占用的 CPU 周期。真正有效的措施有 4 项。

先收集证据。 记录 UTC 时间戳、每次事件的持续时间、重复频率,以及 mpstat 显示的是只有一个 vCPU 受影响,还是所有 vCPU 都受影响。连续记录一周的样本,比一张截图更有价值。

提交包含这些数据的工单。 直接询问两个问题:这些时间段内节点是否存在超额分配,以及能否迁移我的实例。粘贴 vmstat 输出和准确时间。服务商会根据可复现的时间窗口处理问题;只说服务器运行缓慢的工单,通常会收到要求提供具体时间段的回复。你能将多少工作交给服务商处理,是托管型 VPS 与非托管型 VPS之间的实际差异之一。

要求迁移。 将来宾系统迁移到负载较低的节点,是服务商的常规操作,通常只需短暂重启。这种修复不产生额外费用,能够解决常见情况:某个节点恰好同时承载了多个高负载邻居虚拟机。

购买独享 CPU 资源。 独享 vCPU 方案会为你的实例预留 CPU 容量。具体是完整 CPU 核心还是完整硬件线程,取决于服务商。这样邻居虚拟机就不会继续占用你的 CPU 周期,计数器也会保持在 0 或非常接近 0。虚拟机监控程序自身的维护任务仍可能产生少量残余 steal。此方案每月成本更高,但对于无法承受性能波动的工作负载,这是诚实的解决方案。如果仍然不够,或者你还希望独享内存带宽,下一步就是选择独立服务器而不是 VPS。

在等待上述处理期间,可以先减少 steal 带来的影响。运行的工作线程数应少于 vCPU 数量,因为无法获得 CPU 核心的线程只会增加上下文切换。将批处理任务移到节点负载较低的时段运行,你现在的日志可以帮助确定这些时段。然后在相同时间段内使用相同命令再次测量,这样就能判断调整是否有效,而不是凭猜测作出结论。

FAQ

VPS 上正常的 CPU steal time 是多少?

在共享型方案中,短时峰值以及持续低于约 5% 的数值都属于正常情况,因为共享 CPU 意味着主机会在多个来宾之间分配物理核心。持续数小时达到两位数则不正常,建议提交工单。在专用 vCPU 方案中,预期读数应为 0.0 或非常接近该值,因为 hypervisor 的维护任务仍可能占用少量 CPU。因此,持续高于该值就属于应报告的故障。应结合您自己的工作负载判断这个数值:会运行一整夜的批处理作业可以承受 steal time,但延迟敏感型 API 不能。

更大的方案能解决高 steal time 吗?

不能单靠升级方案解决。同一共享节点上的 vCPU 越多,争用同一组繁忙物理核心的虚拟 CPU 就越多,百分比可能完全不变。要消除几乎所有 steal time,需要使用专用 CPU 配额,或迁移到负载更低的节点。繁忙机器上获得更大的份额,仍然只是繁忙机器上的份额。

为什么我的 VPS 明显变慢,但显示的 steal time 却是 0?

常见原因有两个。hypervisor 可能根本不会导出该计数器。具体取决于主机和来宾内核,某些平台会出现这种情况,因此无论主机实际发生什么,该字段都会保持为 0。运行 systemd-detect-virt 查看您使用的平台。否则,瓶颈可能在其他位置:检查 wa 了解存储等待,比较 r 和 nproc 了解您自己的过载情况,并在容器内读取 /sys/fs/cgroup/cpu.stat 检查配额限流。

我可以从服务器内部降低 steal time 吗?

您无法从来宾系统内部更改主机的调度方式。您只能降低它造成的影响。运行的工作线程数应少于 vCPU 数量,这样运行队列中等待未及时提供的核心的任务就会减少。将批处理作业移到节点负载较低的时段。缓存结果,减少实际需要 CPU 处理的请求数量。真正能够消除 steal time 的措施,例如迁移到其他节点或使用专用核心,需要由服务提供商完成。

这篇文章对您有帮助吗?