VPS选NVMe还是SSD,性能差别大吗?
NVMe在IOPS和延迟上优于SATA SSD,但VPS性能还取决于虚拟化层和邻居负载。了解队列深度、网络存储差异,并用fio测出您的实际性能。
VPS 上的 NVMe 是否重要?
当软件发送大量小型读写请求,并等待每个请求完成时,NVMe 对 VPS 很重要。对于提供缓存页面的网站,或主要等待网络响应的程序,NVMe 带来的变化很小。存储介质只是影响因素之一。磁盘前端的 hypervisor,以及共享同一主机的其他 guest,决定了您实际能达到的性能上限。
NVMe 会改变什么,以及不会改变什么
NVMe(non-volatile memory express,非易失性内存标准)不是一种闪存。它是访问闪存所使用的协议和连接方式。NVMe 设备连接到 PCIe(peripheral component interconnect express)通道,并使用 NVMe 协议通信。SATA(serial ATA)SSD 连接到 SATA 链路,并使用 AHCI(advanced host controller interface)协议通信。两者用于存储数据的存储芯片可能完全相同。
两者有两点不同,而且差异都在命令路径,而不是存储介质本身。
队列。 AHCI 为内核提供一个可容纳 32 个命令的命令队列。NVMe 支持数千个队列,实际使用时通常每个 CPU 核心一个,而且每个队列的深度都远大于 32。一个进程每次只读取一个块时,无法感受到这种差异。一个同时发出 64 个读取请求的数据库则可以感受到:在 SATA 上,第 33 个请求必须等待队列空出位置,设备甚至还没看到它;而 NVMe 设备可以接受全部请求并同时处理。
链路宽度。 SATA III 链路的速率为 6 Gbit/s,扣除协议开销后,实际数据速率约为 550 MB/s。无论后端使用何种闪存,这都是固定上限。4 条 PCIe 通道每秒可传输数 GB 数据,因此链路不再成为瓶颈。
延迟通常是最容易产生错误预期的地方。在队列深度为 1,也就是同时只有一个请求在处理时,SATA SSD 完成一次 4k 读取约需 100 到 150 微秒。NVMe 约需 80 到 100 微秒。两者都很快,单个请求的差异不会被实际运行的程序察觉。并发请求增加后,差异才会变得明显。队列深度,即同时处于处理中的请求数量,决定了两种介质的表现是相近还是差异显著。
网络块存储属于第三类,其工作机制不同。写入请求会经过网络发送到存储集群,只有集群保存数据后才会返回确认,因此延迟以毫秒计,而不是以微秒计。换取这种延迟的是持久性:卷的生命周期不受所连接主机影响,并且可以创建快照和调整大小。
典型公开数据:NVMe、SATA SSD 和网络存储
The data behind this chart
[
{
"disk": "Local NVMe SSD",
"iops_4k_read": "184,000",
"p99_latency_ms": 0.4,
"seq_read_mbps": "3,400"
},
{
"disk": "Local SATA SSD",
"iops_4k_read": "90,000",
"p99_latency_ms": 1.2,
"seq_read_mbps": "550"
},
{
"disk": "Network block storage",
"iops_4k_read": "12,500",
"p99_latency_ms": 6.5,
"seq_read_mbps": "250"
}
]本地 NVMe 设备在队列深度为 32 时,常见标称值为 184,000 次随机 4k 读取 IOPS(每秒输入/输出操作数)。在 SATA SSD 上进行相同测试时,标称值通常接近 90,000,原因是其受到单个 AHCI 队列和 6 Gbit/s 链路的限制。网络块存储通常受服务提供商限制,而不是受硬件限制;12,500 是常见的文档上限。
延迟使用用户实际感受到的单位,也能说明相同的问题。p99 读取延迟是指最慢的 1% 请求,其在本地 NVMe 上约为 0.4 ms,在 SATA 上约为 1.2 ms。将网络加入数据路径后,延迟会变为 6.5 ms,超过 NVMe 数据的 10 倍。
顺序读取的差距最大,但参考价值最低:3,400 MB/s,而另一项为 550 MB/s。服务器上几乎没有任务会以全速从头到尾读取一个大型文件。随机读取和延迟这两列,才更能反映数据库、邮件队列或软件包管理器的实际行为。
这些数据的来源,以及您的结果为何会不同
这 3 行数据来自本地设备的厂商数据表,以及网络存储的公开单卷限制,数据截至 2026 年 7 月,且已四舍五入。测试假设块大小为 4k、执行随机读取、队列深度为 32,并使用单个任务;这是厂商通常发布的测试条件。您的 VPS 是共享主机上的来宾实例,因此在您的设备上进行相同测试时,结果通常会更低,并且每次运行都可能不同。应将这些数据理解为三类存储之间的差异特征,而不是必须达到的目标。
哪些工作负载会感知磁盘
一个规则可以解释所有情况:只有在等待磁盘时,工作负载才会感知磁盘。Linux 会将最近使用的文件数据保存在 RAM 的页缓存中,因此第二次读取文件时不会访问存储设备。如果工作集,也就是实际使用的数据,能够放入 RAM,那么首次读取后,后续读取都会变成内存读取。写入则不同。应用通过 fsync() 刷新的任何写入,都必须先写入稳定存储,应用才能继续执行。
会提交事务的工作。 PostgreSQL、MySQL 和 SQLite 会在提交时调用 fsync() 或 fdatasync(),每次提交都会等待设备响应。因此,单个连接的提交速率由写入延迟决定,而不是由带宽决定。刷新耗时 0.2 ms 的设备,每秒允许的提交次数远高于耗时 5 ms 的设备;吞吐量再高也无法改变这一点。当刷新速度跟不上时,MySQL 会在错误日志中记录这一情况:
[Note] InnoDB: page_cleaner: 1000ms intended loop took 4589ms. The settings might not be optimal.PostgreSQL 会在检查点日志行中报告这一情况,其中较大的 sync= 值表示刷新本身较慢:
LOG: checkpoint complete: wrote 8192 buffers (25.0%); write=27.694 s, sync=11.207 s, total=39.001 s会处理大量小文件的工作。 每个文件都会产生元数据操作,而一次大型顺序读取不会产生这些操作。npm install、大型代码仓库中的 git clone、解包容器镜像、Maildir 邮件存储,以及遍历大型目录树的备份,都会将大量时间花在小规模随机访问上。VPS 上的 restic 备份任务 会读取并计算此前未见过的每个文件的哈希值,因此,包含一百万个文件的备份,其耗时与随机读取延迟高度相关。du -sh 也是如此,它只读取元数据,不读取其他内容。
超出 RAM 容量的数据库也属于这一类。索引不再适合放入页缓存后,每次查找都会变成随机读取,磁盘也会重新进入关键路径。
哪些工作负载不会受到磁盘影响
博客或小型公司网站。 页面体积较小,首次请求后页面缓存即可容纳全部内容,瓶颈通常是渲染所需的 CPU 或资源文件的带宽。低流量网站使用 Ubuntu 24.04 上的 LAMP 堆栈时,缓存预热后几乎不会产生磁盘 IO。
媒体流式传输。 一路 4K 流以 40 Mbit/s 的速率读取 5 MB/s。10 路流读取 50 MB/s,即使网络块存储也能轻松提供。在 VPS 上运行 Jellyfin 媒体服务器时,瓶颈是网络出口配额,以及转码时的 CPU,而不是存储介质。
本地模型推理。 在 VPS 上运行 Ollama 以自行托管 LLM时,模型文件只读取一次,之后在 RAM 中运行。NVMe 可将加载 20 GB 模型的时间从几分钟缩短到几秒,但不会改变每秒生成的 token 数,因为该指标受内存带宽和 CPU 限制。
任何需要等待外部服务的工作负载。 如果一个 worker 每个任务需要花费 800 ms 等待 HTTP 请求,换用更快的磁盘也不会提高速度。
虚拟机监控程序为何与存储介质同样重要
您并不直接访问设备,而是访问虚拟机监控程序提供的虚拟磁盘。该磁盘通常通过 virtio 提供,因此这一层的多个决策比 NVMe 和 SATA 之间的差异更重要。
您无法从客户机内部查看存储介质。 lsblk -d -o NAME,ROTA,SIZE,MODEL 显示 vda,但型号为空,因为 virtio 不会传递驱动器标识。cat /sys/block/vda/queue/rotational 报告的是虚拟机监控程序公布的信息,因此其中显示 0 不能证明设备使用闪存。来自 nvme-cli 软件包的 nvme list 在大多数 VPS 上不会列出任何设备,即使主机装满 NVMe 驱动器也是如此,因为您的磁盘是 virtio 设备,而不是 NVMe 设备。服务方案中写明 NVMe,通常描述的是主机所使用的存储介质。您的卷仍可能通过网络连接。
主机缓存模式对数值的影响可能超过存储介质。 如果主机启用了 writeback 缓存,客户机中的 fsync() 可能在主机将数据写入自身 RAM 后立即返回。这样的基准测试结果是任何物理设备都无法达到的。同时,主机崩溃可能导致数据库认为已经安全写入的数据丢失。使用缓存模式 none 时,数值更低,也更符合实际。
限额和突发额度。 许多服务提供商会限制每个卷或每个方案的 IOPS,许多网络卷还使用突发额度。突发额度是一组 credits:额度未耗尽时,卷可以高速运行;额度耗尽后,速度会降至低得多的基线水平。其表现很容易识别。导入或还原任务开始后的几分钟内运行很快,随后突然大幅变慢,并持续保持较低速度,而您的配置没有任何变化。说明突发额度已经用尽。
邻居虚拟机。 在共享主机上,磁盘延迟会随其他客户机的负载变化。这就是需要多次测量的原因。早上运行相同的测试,晚上再次运行,然后比较结果差异。在繁忙的主机上,同一卷两次运行之间的差异通常大于服务商公布的两种存储介质之间的差异。
如何测量 VPS 实际拥有的磁盘容量
安装标准 IO 基准测试工具 fio,然后执行测量。先注意以下三点。测试会创建文件,因此会占用磁盘空间,也会计入计费的 IOPS 配额。测试运行时间应保持较短。不要在承载实时流量的卷上以最大队列深度运行测试,否则测试会与自身应用争用资源。
sudo apt update && sudo apt install -y fio ioping sysstat
cd /var/tmp队列深度为 32 的随机读取,这是服务商通常公布的队列深度:
fio --name=randread --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=32 --numjobs=1 \
--runtime=30 --time_based --group_reporting需要关注的行以 read: 开头。
read: IOPS=184k, BW=719MiB/s (754MB/s)(21.1GiB/30001msec)--direct=1 会绕过客户机页缓存,因此结果反映的是设备性能,而不是 RAM。省略该参数时,测量到的其实是内存性能,返回的数值可能高于任何磁盘能够达到的水平。如果空间足够,请使用 --size=4G 或更大的测试文件,因为 1G 文件可能完全位于主机缓存中,从而使结果看起来偏高。
队列深度为 1 时可以显示原始延迟,这正是单线程进程感受到的延迟:
fio --name=lat --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=1 --runtime=30 --time_based提交测试可以预测数据库行为。它每次写入 4k,并在每次写入后调用 fdatasync(),因此报告的速率包含刷新操作:
fio --name=commit --filename=fio.test --size=1G --bs=4k --rw=randwrite \
--ioengine=psync --fdatasync=1 --runtime=30 --time_based
rm -f fio.test该测试得出的 IOPS 数值接近单个数据库连接每秒能够提交的最大少量事务数,因为提交操作需要等待同一次刷新完成。
如果不使用 fio,也可以快速采样:
ioping -c 20 .--- . (ext4 /dev/vda1) ioping statistics ---
19 requests completed in 4.13 ms, 76 KiB read, 4.60 k iops, 17.9 MiB/s
min/avg/max/mdev = 174.2 us / 217.6 us / 386.1 us / 51.3 usmdev 值表示平均偏差,与平均值同样重要。空闲服务器上的偏差较大,表示存储后端由多个租户共享且当前负载较高。
How to read the result
As of July 2026, these are reasonable readings for a small VPS. Tens of thousands of 4k random read IOPS at queue depth 32, with a queue depth 1 latency under about 0.3 ms, is consistent with local flash. A queue depth 1 latency of several milliseconds means a network path, whatever the plan is called. Sequential reads that stop near 550 MB/s are the signature of a SATA link. A number far above what any single device can do means caching is in the path, almost always on the host.
To see what your live workload is doing to the disk:
iostat -x 1 3
vmstat 1 5
cat /proc/pressure/ioIn iostat -x output, read r_await and w_await, the average milliseconds a request waited, and aqu-sz, the average queue length. Ignore %util on a virtual disk. It reports the share of time at least one request was outstanding, which says nothing about saturation on a device that serves many requests at once, so %util of 100 alongside an r_await of 0.2 ms is a healthy busy disk. In vmstat, the wa column is the percentage of CPU time spent waiting on IO. If /proc/pressure/io exists on your kernel, its some avg10= value is the share of the last 10 seconds in which at least one task was stalled on IO, which is the most direct answer to the question of whether storage is your bottleneck.
磁盘受限的 VPS 表现
高负载平均值、空闲 CPU 以及较大的 wa(位于 vmstat)表示进程正在排队等待磁盘。最明确的内核信号是 dmesg -T 中的这条消息:
INFO: task jbd2/vda1-8:194 blocked for more than 120 seconds.这条消息表示某个内核线程等待存储设备响应超过两分钟,因此 hung task watchdog 记录了该事件。jbd2 是 ext4 日志线程,说明整个文件系统都在等待,而不是某个程序行为异常。在 VPS 上,这通常指向存储后端或已耗尽的 IOPS 配额。
应用层症状也符合这一模式。中位响应时间仍可接受,但最慢请求会形成很长的尾部,因为只有访问磁盘的请求会受到影响。apt upgrade 会在 Unpacking 阶段停留数分钟,因为 dpkg 写入时会执行 flush。在大型仓库中执行 git status 需要数秒。这些属于元数据和 flush 成本,因此增加带宽也无法解决问题。
磁盘成为瓶颈时的处理方法
先购买 RAM,再购买 IOPS。 如果工作集可以放入页缓存,读取操作就不会再访问磁盘。将内存加倍通常比迁移到更快的存储类别更有效,而且成本通常更低。
在数据允许的情况下减少刷写次数。 在 PostgreSQL 中,synchronous_commit = off 可以让提交操作在数据写入磁盘前返回。如果服务器发生故障,最后不到 1 秒的事务可能会丢失。数据库不会损坏,因为预写式日志仍会按顺序写入。对于分析副本,这种取舍是合理的;对于支付业务则不合适。MySQL 中的 innodb_flush_log_at_trx_commit = 2 也是同样的取舍。
批量处理小文件。 传输或备份 1000000 个小文件时,耗时主要由每个文件的单独处理开销决定。因此,在高延迟存储上,先进行归档再传输一个数据流,比逐个复制整个目录树更快。
确保精简卷上的 discard 正常工作。 在精简配置的存储上,后端只有在文件系统通知后才知道某个块已释放;如果卷从不执行 trim,写入性能会逐渐下降。Ubuntu 提供了一个每周运行的定时器:
systemctl status fstrim.timer
sudo fstrim -avfstrim -av 会输出每个挂载点执行 trim 的字节数。如果提示不支持 discard,说明虚拟磁盘没有将 discard 传递到主机,因此无需修复。
不要调整 IO scheduler。 对于 virtio 磁盘,cat /sys/block/vda/queue/scheduler 通常已经显示 none,实际调度发生在主机上,而您无法访问主机。也不要调整 noatime:Ubuntu 默认使用 relatime 挂载,这已经避免了几乎所有 atime 写入。
选择方案
当数据库、邮件服务器、CI runner 或依赖大量软件包的构建任务运行在该服务器上时,应为 NVMe 付费。对于缓存型网站,或主要耗时在外部调用上的应用,不要为此支付额外费用。如果无法确定,磁盘可能不是瓶颈,因为大多数小型 VPS 工作负载首先会耗尽 RAM 或带宽。
在第 1 天进行测量,同时完成新 VPS 上的前 10 分钟,并将输出保存到文件中。基线数据可用于之后证明主机变慢,而不是代码导致性能下降。优先选择明确说明存储类型和 IOPS 上限的提供商。如果方案标注为 NVMe,但队列深度为 1 的读取耗时 4 ms,那么你使用的是配备 NVMe 主机上的网络存储。这种产品可以销售,但它与真正购买 NVMe 存储是两回事。
FAQ
NVMe 在 VPS 上是否总是比 SATA SSD 更快?
不是。在队列深度为 1 时,两者性能接近,4k 读取延迟大约为 80 到 150 微秒,单线程程序无法区分它们。存在大量并发请求时,NVMe 才会体现优势,因为 AHCI 只有一个可容纳 32 个命令的队列,而 NVMe 提供数千个更深的队列。在共享主机上,其他租户产生的负载对延迟的影响可能大于存储介质本身,因此应使用 fio 测量自己的卷,而不要只看方案名称。
如何检查 VPS 是否确实使用 NVMe?
无法直接检查,因为 virtio 会隐藏物理设备。lsblk 显示 vda,但不包含型号字符串;nvme list 不返回任何内容;/sys/block/vda/queue/rotational 只报告 hypervisor 对外公布的信息。应改为测量实际行为。队列深度为 1 的随机 4k 读取延迟低于约 0.3 ms,说明使用的是本地闪存。延迟达到几毫秒,说明链路中存在网络跳转。顺序读取速度接近 550 MB/s 后停止,通常表示使用 SATA 链路。
NVMe 会让我的网站加载更快吗?
通常不会。首次请求之后,Linux 会从内存中的页面缓存提供文件,磁盘因此处于空闲状态。小型 VPS 的页面速度通常受应用 CPU 时间和带宽限制。如果网站在每次请求时都写入磁盘,磁盘就会重新进入关键路径。例如,数据库驱动的购物车频繁提交事务时,每次提交都必须等待 flush 完成。
VPS 的 fio 测试结果达到什么水平才算好?
截至 2026 年 7 月,本地闪存上的小型 VPS 通常可在队列深度为 32 时达到数万 IOPS 的 4k 随机读取性能,队列深度为 1 时的延迟低于 0.3 ms。网络块存储通常只能达到几千 IOPS,延迟为几毫秒。应在不同时间分别运行 3 次测试。多次结果之间差异较大,比平均值更能说明问题,因为这表明主机上其他租户对你的影响有多大。
应该将数据库放在网络块存储上吗?
可以,许多托管服务也这样做,但提交路径会受到影响。每次 flush 都要经过网络,因此单个连接每秒提交的小事务数量会少于使用本地闪存时的数量。作为交换,你可以获得即使主机故障也能保留的数据持久性。如果为写入密集型数据库选择网络存储,应将多个操作合并为更大的事务,让更少的 flush 携带更多行。