如何正确进行 VPS 基准测试:工具选择与结果分析
VPS 基准测试不仅是运行 yabs.sh,更需手动执行 fio、sysbench 和 iperf3。本文详解如何通过监控 steal time 指标识别超卖现象,并教你解读 CPU 配额限制与虚拟化类型对性能的影响,助你获取真实的硬件表现数据。
基准测试 VPS 的含义
基准测试 VPS 时,您需要测量四个指标:单核 CPU 的运行速度、机器的内存带宽、存储设备每秒处理的小型随机磁盘操作数,以及网络链路的吞吐量。运行一次 yabs.sh 即可在大约 10 分钟内获得这四个指标。解读结果更为困难,因为 VPS(虚拟专用服务器)与其他租户共享物理硬件,同一台机器在 03:00 和 20:00 测得的数据可能大相径庭。
本方案计划先运行 yabs.sh 以获取快速概览,随后手动运行其底层的工具。亲自运行这些工具,您可以更改某个标志(flag)、观察数值变化,并了解该数值实际衡量的指标。请在机器配置完成后进行测试,而非配置前。新 VPS 的前十分钟中的步骤应优先执行,因为一台仍在进行首轮更新的服务器,其基准测试表现不佳的原因与硬件无关。
在测量机器前先进行检查
基准测试结果不准确,有一半是因为作者不了解所使用的机器。
nproc
lscpu | grep -E 'Model name|Hypervisor|Thread'
free -h
df -hT /
uname -r
systemd-detect-virtHypervisor vendor: KVM 表示完全虚拟化,因此您运行的是自己的内核。systemd-detect-virt 输出 lxc 或 openvz 则表示容器虚拟化:您与宿主机共享内核,且 CPU 和内存限制是通过 cgroup(控制组)设置而非虚拟硬件实现的。在 cgroup v2 系统上,您可以直接读取 CPU 限制。
cat /sys/fs/cgroup/cpu.maxmax 100000 表示没有配额限制。200000 100000 表示您在每 100000 微秒周期内可以使用 200000 微秒的 CPU 时间,即相当于两个核心的配额。如果一个方案标称为 4 vCPU 但配额仅为两个核心,其性能永远无法达到四个核心的水平,且没有任何基准测试工具会明确指出原因。
df -hT / 的重要性在于另一个原因:Type 列。如果该列显示 overlay,说明您处于容器内部,下方的磁盘测试需要进行相应调整。请务必记录这一点。
持续监控 steal time
Steal time 指的是虚拟 CPU 已就绪但 Hypervisor 将物理核心分配给其他租户的时间占比。这是判断性能结果是由邻居租户影响还是由硬件本身引起的最有效单一指标。
vmstat 1 10查看右侧的 st 列。数值稳定在 0 或 1 是正常现象。如果数值持续高于 5,说明宿主机当前处于超卖状态,此时记录的所有 CPU 数据均因非本机原因而偏低。top 显示的数值与 CPU 行上的 %st 相同。在进行基准测试时,请在第二个 SSH 会话中保持运行 vmstat 1,并将每个测试结果旁记录下对应的 steal 数值。
从 yabs.sh 开始
yabs.sh (Yet Another Bench Script) 是一个 shell 脚本。它会下载 fio、iperf3 和 Geekbench 的静态二进制文件,运行测试并输出一份汇总报告。它是 VPS 基准测试讨论中的通用语言,因此 yabs 的输出结果是与他人对比性能的最快方式。
该项目提供的单行运行命令如下。
curl -sL yabs.sh | bash该命令将 URL 返回的内容直接通过管道传输给 shell 执行。建议先下载并阅读脚本内容,确认无误后再运行。
curl -sLo yabs.sh https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/yabs.sh
less yabs.sh
bash yabs.sh在使用管道传输时,标志位需置于 -s -- 之后;若运行本地脚本,则直接置于文件名之后。常用的标志位包括:-f 跳过磁盘测试,-i 跳过网络测试,-g 跳过 Geekbench 测试,-r 将 iperf3 测试节点缩减为两个,-j 以 JSON 格式输出结果,-w results.json 将 JSON 结果写入文件。
bash yabs.sh -r -w yabs-run1.json首次运行前需注意两点。Geekbench 会上传测试结果并生成一个公开的 browser.geekbench.com 链接,持有该链接的任何人均可查看您的 CPU 型号及分数。-g 可完全跳过此项测试。其次,iperf3 阶段会向多个地区的服务器传输真实流量,这会消耗您的月度带宽配额。在 1 Gbit/s 的链路上,完整的网络测试阶段可能会产生数十 GB 的流量,因此在配额较小时请使用 -r,在按量计费的链路上请使用 -i。
yabs 输出各部分的含义
磁盘部分使用 fio 运行 50/50 的读写混合测试,块大小分别为 4k、64k、512k 和 1m。它会报告每种块大小的 IOPS(每秒输入/输出操作数)和带宽。对于数据库、邮件服务器或任何执行大量小规模写入的任务,应重点关注 4k 行,因为大多数服务器 IO 都是小规模且分散的。1m 行适用于备份和视频处理,这些场景涉及长字节流的传输。
网络部分使用 iperf3 对多个地区的公共服务器进行双向并行流测试。此处数值较低时,应将其视为一个疑问而非定论,因为公共 iperf3 服务器是共享的且经常处于饱和状态,测试结果不佳可能是由远端造成的。
Geekbench 部分提供单核分数和多核分数。单核分数预测单个请求、编译或查询的完成速度。多核分数主要反映服务器实际拥有的核心数量。
磁盘:自行运行 fio
fio (flexible IO tester) 是 yabs 磁盘测试部分底层的工具。直接使用该工具时,各个标志位才具有实际意义。
sudo apt update && sudo apt install -y fio sysbench iperf3在您实际使用的文件系统上,执行队列深度为 32 的 4k 随机读取测试:
fio --name=randread4k --filename=./fio-testfile --size=2G --bs=4k \
--rw=randread --ioengine=libaio --iodepth=32 --direct=1 \
--runtime=60 --time_based --group_reporting输出结果中的摘要行如下所示。
read: IOPS=184k, BW=719MiB/s (754MB/s)(42.1GiB/60001msec)fio 会在下方打印一个 clat percentiles 块。99.00th percentile(第 99 百分位)是值得参考的数据,因为它代表了百分之一最慢请求的等待时间。平均延迟会掩盖用户实际感知的卡顿。
--direct=1以O_DIRECT模式打开文件,使读取操作绕过内核页缓存。如果不使用此选项,在拥有 8G 内存的机器上对 2G 文件进行第二次扫描时,数据将直接从内存读取,导致 fio 报告的 IOPS 达到数百万。该数值是真实的,但它反映的是内存性能。--ioengine=libaio提交异步请求,这使得--iodepth=32能够保持 32 个请求同时处于处理中。如果使用psync等同步引擎,大于 1 的 iodepth 将无效,测试将变为一次处理一个请求。--time_based --runtime=60运行固定的 60 秒而非处理固定工作量,确保快速磁盘和慢速磁盘在相同的挂钟时间内进行测试,从而保证对比的公平性。--size=2G设置测试文件大小。请确保该值大于路径中任何缓存的大小,并提前检查是否有足够的剩余空间。
随机写入测试使用带有 --rw=randwrite 的相同命令。请单独运行该测试,并在结束后删除文件。
fio --name=randwrite4k --filename=./fio-testfile --size=2G --bs=4k \
--rw=randwrite --ioengine=libaio --iodepth=32 --direct=1 \
--runtime=60 --time_based --group_reporting
rm -f ./fio-testfile若要模拟更接近真实流量的混合负载,请使用 --rw=randrw --rwmixread=70。您所使用的存储类型对结果的影响远超任何标志位,相关差异已在 VPS 上 NVMe 与 SATA SSD 存储的区别 中说明。
当 fio 因 Unknown error -1 而停止时
并非所有文件系统都支持直接 IO(Direct IO)。overlay 是 Docker 默认提供给容器的文件系统,且多种网络文件系统不支持 O_DIRECT,因此 libaio 提交的请求内核无法完成,导致 fio 报错退出:
fio: io_u error on file ./fio-testfile: Unknown error -1: read offset=0, buflen=4096
fio: pid=1234, err=-1/file:ioengines.c:321, func=get_events, error=Unknown error -1请先运行 df -hT .。如果 Type 列显示为 overlay,请将 --filename 指向实际存储路径(例如绑定挂载的卷),或者直接在宿主机上运行 fio,而不是在容器内运行。如果无法使用实际存储,进行一次带缓冲的同步运行至少可以验证命令本身是否正确。
fio --name=randread4k-buffered --filename=./fio-testfile --size=256M --bs=4k \
--rw=randread --ioengine=psync --direct=0 --numjobs=1 \
--runtime=15 --time_based --group_reporting
rm -f ./fio-testfile请如实说明该运行结果的性质。在首次运行后,256M 的文件会驻留在页缓存(page cache)中,因此 IOPS 数值反映的是内存性能。仅使用此方法确认 fio 已安装且标志解析正确。切勿将其作为磁盘测试结果引用。
为什么 dd 不适合作为磁盘基准测试工具
dd 在许多 VPS 讨论帖中频繁出现,它仅能回答一个非常局限的问题。
dd if=/dev/zero of=./ddtest bs=1M count=1024 oflag=direct conv=fdatasync
rm -f ./ddtest该命令仅测量单线程且单请求并发下的顺序写入吞吐量。它作为一项基础的完整性检查是合理的。但它无法反映随机 IO 的性能,也无法体现 32 个请求同时到达时的表现。如果忽略 oflag=direct,它测量的主要是内核接收写入数据到内存的速度,这就是为什么论坛帖子中引用的 dd 数值往往极其离谱。
CPU: sysbench cpu
sysbench cpu --cpu-max-prime=20000 --threads=1 run
sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run需要关注的数值是 events per second。首先运行单线程测试。该数值决定了单个 PHP 请求或单个编译任务的完成速度,也是同价位主机之间差异最大的指标。随后运行全线程测试,以判断您的 vCPU 是独立的物理核心,还是单个核心的切片。
请明确此测试的衡量对象:sysbench cpu 通过 64 位整数运算重复寻找素数。它不会以任何类似于真实工作负载的方式对内存带宽、向量单元或缓存施加压力,因此它适用于对比两台主机的性能排名,但不适用于预测您的应用程序运行表现。
Ubuntu 24.04 搭载的 sysbench 版本为 1.0.20,在该版本中测试名称需置于首位。如果从旧文章中复制带有 --test=cpu 的命令,将会得到 WARNING: the --test option is deprecated 错误。sysbench 0.4 和 sysbench 1.0 的评分完全不可比,因此切勿将您的测试结果与未注明版本的公开数据进行对比。
内存:sysbench memory
sysbench memory --memory-block-size=1M --memory-total-size=20G --memory-oper=write --threads=1 run
sysbench memory --memory-block-size=1M --memory-total-size=20G --memory-oper=read --threads=1 run结果单位为 MiB/sec,在所有机器上读取速度均快于写入速度。请将 --memory-block-size 保持在 1M,并在对比的所有主机上保持一致。在 1K 时,数值会大幅下降,因为单次操作的开销增加了 1000 倍,此时测得的是循环开销而非内存带宽。这是已发布的内存测试分数中最常出现设置不匹配的标志。
网络:iperf3
测试吞吐量的可靠方法是针对您控制的第二台机器进行测试,因为这样您可以了解两端的状态。
在远端:
iperf3 -s该命令会在 TCP 5201 端口进行监听。请仅针对您进行测试的地址开放该端口,并在测试完成后将其关闭。VPS 的基本 ufw 防火墙规则 涵盖了相关语法。
在待测 VPS 上:
iperf3 -c 203.0.113.10 -t 30
iperf3 -c 203.0.113.10 -t 30 -R
iperf3 -c 203.0.113.10 -t 30 -P 8第一个命令测量从待测机器发出的上传速度。-R 会反转方向,从而测量下载速度。-P 8 会开启 8 个并行流。
请同时运行单流和并行版本,因为它们回答的问题不同。单个 TCP 连接所能承载的未确认数据量受限于其窗口大小,因此其上限大致为窗口大小除以往返时间。在 80 ms 延迟和 4 MB 窗口的情况下,无论底层链路速度有多快,其上限约为 400 Mbit/s。单流数据反映了单个下载任务的实际速度。并行数据则反映了链路的总容量。
执行此操作时,请留意您的带宽配额。以 1 Gbit/s 的速度运行 30 秒会消耗约 3.75 GB 流量,且您需要在每个方向上多次运行测试。
参考数据及解读方法
The data behind this chart
[
{
"device": "Local NVMe",
"iops_4k_read": "180,000"
},
{
"device": "Local SATA SSD",
"iops_4k_read": "90,000"
},
{
"device": "Network block",
"iops_4k_read": "12,000"
},
{
"device": "Spinning disk",
"iops_4k_read": "180"
}
]在已发布的测试结果中,本地 NVMe 卷的 4k 随机读取 IOPS 通常接近 180,000。本地 SATA SSD 的数值约为 90,000。网络附加块存储(即每个请求在到达磁盘前均需经过网络传输)的数值接近 12,000,而机械硬盘由于每次随机请求都需要移动物理磁头,其性能大约为 180。
上述数据是各类存储的典型发布值,而非来自单一主机的测量结果。请仅将其用于一个目的:核实您的测试结果是否处于正确的数量级。如果标称为 NVMe 的方案在 4k IOPS 测试中仅达到数千的量级,请首先确认 --direct=1 是否已开启。如果已开启,则说明该存储设备与产品页面描述不符,或者您正与负载极高的邻居共享该资源。
为什么单次运行不能作为基准测试
单次结果只是共享机器在某一分钟内的快照。请将其视为一个样本。
- 每次测试至少运行 5 次,分布在不同时间段,且至少跨越 2 天。保留中位数和离散度。未提供离散度的数据仅为营销数字。
- 记录每次运行的窃取时间(steal time)。剔除
st过高的运行结果,或者至少对其进行标注。 - 以两种时长运行磁盘测试。许多方案提供随时间恢复的突发 IOPS 配额,因此 60 秒的 fio 运行测量的是突发性能,而
--runtime=600测量的是基准性能。基准性能是您在最差情况下的实际表现。 - 确保没有其他程序在运行。在 CPU 测试期间启动
unattended-upgrades的 apt 事务会严重影响分数,而在每次运行前执行ps -e -o comm= | grep -E 'apt|dpkg'只需一秒钟。 - 每次只更改一个变量。不同的工具版本、块大小或线程数产生的数据无法进行比较,无论它们看起来多么相似。
当您比较两个服务提供商时,请在同一天的同一时间运行测试。否则,您测量的是时间因素而非性能。
最后对您的工作负载进行基准测试
合成工具仅用于对机器进行排名。只有您自己的工作负载才能判断机器是否足够。请为您实际执行的任务计时。
time tar -czf /tmp/bench.tgz /usr/share
rm -f /tmp/bench.tgz该操作会压缩几百兆字节的数据,因此它会同时测试 CPU 和磁盘,并且在两者中任何一个发生变化时都会受到影响。出现 Removing leading / from member names 警告是正常的。更好的做法是,为您自己的构建过程、最慢的查询或页面渲染进行计时。如果一个构建在某台主机上耗时 4 分钟,而在另一台主机上耗时 7 分钟,那么无论 Geekbench 的结果如何,结论都已经确定。这也是衡量何时增加机器配置不再具有性价比的指标,在您阅读 VPS 的实际月度成本 或将工作负载迁移到 独立服务器 之前,了解这一点非常重要。
FAQ
为什么每次运行基准测试得到的结果都不一样?
VPS 与其他租户共享物理 CPU、存储和网络资源,因此测试结果取决于其他租户当下的负载情况。在测试期间运行 vmstat 1 并查看 st 列:如果持续的 steal time 超过 5,说明宿主机负载过高,导致 CPU 得分偏低,这并非由您的机器配置引起。解决方法在于测试方法而非调优。请在不同时段运行测试至少 5 次,然后报告中位数及数据分布范围。
为什么 fio 报告的 IOPS 高达数百万?
这几乎总是因为缺少 --direct=1 参数。如果不加此参数,fio 会通过内核页缓存读取数据,因此在首次运行后,2G 的测试文件会直接从内存中读取,您测得的实际上是内存带宽。请添加 --direct=1 参数,并确保测试文件大小超过路径中任何缓存的大小。如果此时 --direct=1 报错 err=-1/file:ioengines.c:321, func=get_events, error=Unknown error -1,请运行 df -hT .:Type 为 overlay 的环境不支持 O_DIRECT,请将测试指向真实的存储设备。
只使用 yabs.sh 就足够了吗?
作为初步评估,足够了。它会以 4 种块大小运行 fio,双向运行 iperf3,并执行 Geekbench,最后输出一份易于阅读的汇总报告。当您需要深入分析数值背后的原因时,它就不够用了,因为您无法针对每个测试修改其标志位。一旦 yabs 的结果出现异常,请直接使用 fio 或 sysbench 进行复现,并逐个修改标志位进行排查。
哪个单一指标能预测应用程序的实际体验?
对于大多数 Web 和数据库工作负载,依次是单核 CPU 速度和 4k 随机读取延迟。吞吐量数据看起来很亮眼,但通常不具备决定性,因为典型的请求都很小。请引用 fio clat percentiles 块中的 99th percentile(99 分位值)而非平均值,因为用户感知到的往往是那百分之一的慢请求。
基准测试前需要安装什么吗?
fio、sysbench 和 iperf3 均包含在 Ubuntu 和 Debian 的软件仓库中:sudo apt install -y fio sysbench iperf3。yabs.sh 仅需 curl,因为它会自动下载缺失组件的静态二进制文件。测试完成后请删除所有测试文件,因为在 20G 的磁盘上遗留一个 2G 的 fio 测试文件,几周后可能会触发磁盘空间不足的告警。