VPS CPU steal time 与邻居干扰如何判断
了解 CPU steal time 的准确含义,读取 vmstat 的 st 列,并区分 noisy neighbour、共享 vCPU 限制与您自己的 CPU 过载,避免误判。
CPU steal time 的实际含义
CPU steal time 表示虚拟 CPU 已准备好运行、没有任何等待项,但 hypervisor 将物理核心分配给了其他 guest 的时间占比。任务已经排队。物理核心正在别处运行。Linux 会单独统计这些周期,并将其报告为 st。借此可以区分“服务器正忙”和“服务器正在等待调度”。
这正是该计数器存在的原因。自身进程占用 CPU 的时间报告为 us(user)或 sy(system)。任务因存储操作而阻塞的时间报告为 wa(I/O wait)。如果 vCPU(virtual CPU)处于可运行状态、位于运行队列中、没有未完成的 I/O,但仍未执行,则报告为 st。服务器内部无法清除这种状态,因为调度决策是在更底层的 host 上完成的。
这直接对应于VPS 如何在多台 guest 之间共享一台物理机。通常原因是邻居 guest:同一节点上的另一个 guest 负载很高,因此 host 在多个 guest 之间分配物理核心。还有一个容易被忽略的原因。许多提供商会将共享 vCPU 限制为物理核心的一部分;在多个 hypervisor 中,这种强制限制会在 guest 内部计入 steal。因此,较高的 st 读数表示物理核心没有分配给您,但不一定能说明是谁占用了它。
抢占时间数值的来源
内核本身无法测量抢占时间,因为它无法看到宿主机。该数值由虚拟机监控程序提供。在 KVM 中,宿主机会将每个 vCPU 的计数器写入与客户机共享的页面;当内核启用 CONFIG_PARAVIRT_TIME_ACCOUNTING 构建时,客户机会将这些计数器累加。所有发行版内核都启用了该选项。Xen 通过其运行状态区域报告相同的数据。该总计值只会通过一个位置提供给用户空间:
head -1 /proc/statcpu 行包含 10 个计数器,单位是自启动以来的 USER_HZ 时钟滴答,顺序如下:user、nice、system、idle、iowait、irq、softirq、steal、guest、guest_nice。steal 是标签后的第 8 个值。下面的每个工具,包括 vmstat、top、mpstat 和任何 Prometheus 导出器,都会读取同一个字段,并根据两次采样计算百分比。
其中一个后果比其他问题都更重要。如果虚拟机监控程序从不导出该计数器,该字段就会永久保持为 0,所有基于它的工具都会报告平静的 0.0,即使宿主机已经过载。KVM 和 Xen 会导出该计数器。在 VMware 和 Hyper-V 上运行的客户机通常会持续报告 0。在信任 0 之前,先检查平台:
systemd-detect-virt该命令会输出平台名称,例如 kvm、xen、vmware 或 microsoft;在裸机上则输出 none。在容器内,它会改为报告运行时,例如 lxc、docker 或 podman。这只能说明容器的情况,不能说明其下方的主机。在 kvm 上,0 确实说明宿主机没有让你的实例受到明显影响。在从不填充该字段的平台上,0 完全不能作为判断依据;必须通过为实际工作计时来判断资源争用。
如何检查 VPS 上的 CPU steal time?
vmstat 来自 procps 软件包。几乎所有 Ubuntu 和 Debian VPS 镜像都已包含它,但某些精简容器镜像中可能没有,因此在依赖它之前请先安装。
sudo apt-get update
sudo apt-get install -y procps
vmstat --version
vmstat 1 5vmstat --version 会输出类似 vmstat from procps-ng 4.0.4 的一行内容。如果能输出该内容,说明工具已安装,并且读取的是内核的真实计数器。vmstat 1 5 随后会每秒采集一次,共采集五次。
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 位于倒数第二列,而不是最后一列。请根据列标题读取该列,因为不同版本之间的列位置可能发生变化。
以下两个习惯有助于确保读数准确。第一行数据是系统自启动以来的平均值,因此应忽略这一行,读取后续各行。一次采样不能代表实际情况,因为 steal time 可能集中出现:运行 vmstat 1 60,持续观察完整的一分钟后再下结论。
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 5mpstat 会为每个 CPU 输出一行,其中包含 %steal 列,用于显示是每个 vCPU 都受到影响,还是只有一个 vCPU 受到影响。如需保留支持工单所需的历史记录,请保存采样结果,而不是只查看屏幕上的输出:
date -u | tee -a ~/steal.log
mpstat -P ALL 1 5 | tee -a ~/steal.log在你怀疑出现问题的时段内通过 cron 运行该命令。这样,文件中就会有准确的十分钟记录,而不只是向服务提供商描述“昨晚感觉很慢”。
窃取时间数值代表什么?
- 稳定的
0.0。 状态正常,或者平台根本不报告窃取时间。庆祝之前,先使用systemd-detect-virt确认。 - 持续数秒、达到几个百分点的峰值。 在任何共享节点上都很正常。邻居节点开始构建任务,或者主机正在运行备份。
- 共享方案中持续保持 1 到 5 percent。 这是预期情况。共享 CPU 的价格已经反映了这一点。
- 持续保持 5 到 10 percent。 这会造成可测量的性能下降。开始记录证据,并比较连续数天相同时间段的数据。
- 每次持续数小时、超过 10 percent。 对您的工作负载而言,该节点的资源分配过度。这种程度足以提交支持工单或迁移服务。
请将这些区间作为解读指南,而不是规格标准,因为没有服务提供商会为共享方案发布窃取时间保证。请结合您运行的工作负载进行判断。夜间批处理任务可以承受 15 percent 的窃取时间而不易被察觉。延迟敏感型服务会在平均值看起来异常之前,先在 p99 中体现出来。因此,交易机器人等延迟敏感型工作负载应运行在专用 CPU 核上。
抢占时间会带来多大开销?
计算很简单。如果有 s 的 CPU 时间被抢占,需要固定 CPU 时间的任务在实际经过的时间上会变为原来的 1 / (1 - s) 倍。对于需要 60 秒 CPU 时间的任务:
The data behind this chart
[
{
"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 percent 时,这是普通共享型套餐中的读数,任务需要 61.9 秒,而不是 60.0 秒。通常不会有人因为这个差异提交工单。在 8 percent 时,需要 65.2 秒。在 40 percent 时,同一个任务需要 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.statnr_throttled 统计该组达到 CPU 配额的执行周期数,throttled_usec 统计该组被冻结的总时间。nr_throttled 上升表示您的进程处于可运行状态但未获得运行机会,体验上与 steal 相同,但原因是您自行设置了限制。请先检查您自己的限制,再判断是否应归咎于宿主机,尤其是当您在 VPS 上 使用 Docker 运行服务 且 compose 文件中设置了 CPU 限制时。分层虚拟化会增加一个额外的时间损耗位置,因为 VPS 内的虚拟机既要承受自身的 steal,也要承受其自身的调度延迟。如果您在 VPS 上 运行嵌套虚拟化,请牢记这一点。
如何处理持续的 steal
Guest 内部没有任何设置可以修复 steal,因为作出调度决策的 scheduler 在 guest 外部。实际可行的措施有 4 项。
先收集证据。 记录 UTC 时间戳、每次事件的持续时间、重复频率,以及 mpstat 是否显示只有一个 vCPU 受影响,还是所有 vCPU 都受影响。持续记录一周的样本比一张屏幕截图更有价值。
提交包含这些数据的工单。 直接询问两个问题:这些时间段内该节点是否存在资源超售,以及是否可以迁移我的实例。粘贴 vmstat 的输出和准确时间。服务商会根据可复现的时间窗口处理问题;只写“服务器很慢”的工单通常会被要求补充这些信息。您可以将多少工作交给服务商处理,是 托管 VPS 与非托管 VPS 之间的实际差异之一。
要求迁移。 对服务商来说,将 guest 迁移到负载较低的节点是常规操作,通常只需短暂重启。这种修复不产生额外费用,适用于最常见的情况:某个节点恰好同时承载了多个高负载邻居。
购买独享计算资源。 Dedicated vCPU 方案会为您的实例预留物理核心,因此该计数器会归零并保持为 0。每月费用更高,但对于无法承受性能波动的工作负载,这是直接有效的方案。如果这仍然不够,或者您还希望独享内存带宽,下一步就是选择 专用服务器而不是 VPS。
在等待处理期间,您可以先减少 steal 带来的影响。运行数量少于 vCPU 数量的 worker 线程,因为无法获得核心的线程只会增加上下文切换。将批处理任务移到节点较空闲的时段,您现在的日志可以帮助确定这些时段。然后使用相同的命令,在相同的时间段再次测量,以便确认调整是否有效,而不是凭猜测判断。
FAQ
VPS 上正常的 CPU steal time 是多少?
在共享套餐中,短暂的峰值和持续低于约 5 percent 的数值都属于正常现象,因为共享 CPU 意味着主机会在多个虚拟机之间分配物理核心。持续数小时处于两位数则不正常,值得提交工单。在 dedicated vCPU 套餐中,预期读数是 0.0,因此出现其他数值就应报告为故障。应结合您自己的工作负载判断该数值:夜间批处理作业可以承受 steal time,而对延迟敏感的 API 则无法承受。
扩大套餐能解决高 steal time 吗?
不能单靠扩大套餐解决。在同一个共享节点上增加 vCPU,只会让更多虚拟 CPU 争用同一组繁忙的物理核心,百分比可能完全不变。能够消除 steal time 的方式是使用 dedicated CPU 分配,或迁移到负载较低的节点。繁忙主机上获得更大的份额,仍然只是繁忙主机上的份额。
VPS 明显变慢,但显示 0 steal time,为什么?
通常有两个原因。虚拟机管理程序可能根本不提供该计数器。VMware 和 Hyper-V 平台通常如此,因此无论主机发生什么,该字段都会保持为零。运行 systemd-detect-virt 查看您使用的平台。否则,瓶颈可能在其他位置:检查 wa 了解存储等待,比较 r 和 nproc 了解您自己的过载情况,并在容器中读取 /sys/fs/cgroup/cpu.stat 检查配额限流。
可以从服务器内部降低 steal time 吗?
您无法从虚拟机内部更改主机的调度方式。您只能降低它造成的影响。运行的 worker 线程数应少于 vCPU 数量,这样较少的任务会在 run queue 中等待尚未空闲的核心。将批处理作业移到节点负载较低的时段。缓存结果,减少实际需要 CPU 处理的请求。真正能够消除 steal time 的措施,例如迁移到其他节点或使用 dedicated cores,需要由服务提供商执行。