我们售卖的每一个套餐,从 $3.29 的 VPS 到最大的独立服务器,都运行在 NVMe 上。这是定价页面上的一句话;而本文,就是这句话背后的证据。我们在自己的生产宿主机、上一代的 SATA SSD 阵列,以及一个客户可直接使用的 VPS 切片上,运行了同样的 fio 测试配置,并说明其中哪些数字才是您的数据库真正能感受到的。
测试方法
所有测试均使用 fio 3.36、直接 I/O,并用 16 GB 的测试文件来绕开缓存;每轮在 30 秒预热之后运行 60 秒,取三轮的平均值。三套被测系统如下:
- NVMe 宿主机:两块企业级 NVMe 硬盘(PCIe 4.0,3 DWPD)组成软件镜像,这是我们 VPS 宿主机采用的配置,也是独立服务器的默认配置。
- SATA 宿主机:四块企业级 SATA SSD,通过硬件控制器组成 RAID 10,这是我们在 2023 年淘汰的配置。
- VPS-4:运行在 NVMe 宿主机上的 KVM 客户机,采用标准的 IOPS 配额,在客户机内部通过 virtio-blk 测得。
测试结果
| 测试项 | NVMe 宿主机 | SATA 宿主机 | VPS-4 客户机 |
|---|---|---|---|
| 随机 4k 读,QD1,延迟 p50 | 68 µs | 142 µs | 95 µs |
| 随机 4k 读,QD1,延迟 p99 | 110 µs | 390 µs | 210 µs |
| 随机 4k 读,QD32,IOPS | 612,000 | 178,000 | 40,000(配额) |
| 随机 4k 写,QD1,延迟 p99(fsync) | 28 µs | 620 µs | 70 µs |
| 随机 4k 写,QD32,IOPS | 380,000 | 72,000 | 20,000(配额) |
| 顺序读,1 MB,MB/s | 6,900 | 2,050 | 1,800(配额) |
| 顺序写,1 MB,MB/s | 4,200 | 1,600 | 900(配额) |
| 70/30 混合读写 4k,QD16,IOPS | 420,000 | 105,000 | 32,000(配额) |
VPS 这一列受策略限制,而不是受硬件限制:每台客户机都有各自的配额,这样就没有哪个邻居能把整台宿主机吃光。这个配额,正是这次对比的重点。一台跑到上限的 VPS-4,在延迟上依然胜过整个 SATA 阵列,而延迟才是真正重要的数字。
为什么看延迟,而不是吞吐量
一个访问数据库的 Web 请求,会执行一连串彼此依赖的小块读取:先读一个索引页,再读一个堆页,接着为了做连接再读另一个索引。每一次读取都是 4k 或 8k,必须完成之后下一次才能开始,所以请求的耗时是这些延迟的总和,而不取决于带宽。一个涉及 200 个页面的查询,在中位数水平上,NVMe 上耗时 14 ms,SATA 上耗时 28 ms;而在第 99 百分位上的差距,就是用户感受到的“有时候很慢”。
写入的情况更糟。每一个提交的事务,最后都要对预写日志执行一次 fsync。在 SATA 阵列上,这一步的 p99 是 620 µs;在 NVMe 上则是 28 µs。一个繁忙的 PostgreSQL 每秒要完成 2,000 次提交,那么每一秒里有 1.2 秒耗在等待 SATA 的 fsync 上,在 NVMe 上则只有 56 ms。这就是“我们需要更大的服务器”和“一切正常”之间的全部差别。
不同数据库的实际感受
- PostgreSQL:关键在提交延迟和索引页的随机读。有了 NVMe,您可以放心保持
synchronous_commit = on,不必为此付出代价;而在 SATA 上,人们往往会把它关掉,靠牺牲持久性来换回速度。 - MySQL / MariaDB:InnoDB 的 redo log 具有同样的 fsync 特征,而 doublewrite buffer 会让 SATA 的写入代价再翻一倍。
- Redis:主要在内存里运行,但在磁盘较慢时,
appendfsync everysec会造成短暂的阻塞,表现为周期性的延迟尖峰;换成 NVMe,这种尖峰就消失了。 - ClickHouse、Elasticsearch:合并和大范围扫描看重的是顺序吞吐量;两者都接近宿主机的顺序读写上限,在这种负载下,独立服务器上不设限的 NVMe,相比 VPS 的配额更能物有所值。
- SQLite:单写者模型,每个事务一次 fsync;在 SATA 上感觉很慢,在 NVMe 上,一台 $3 的 VPS 每秒就能处理数千次写入。
“吵闹邻居”与配额
与按客户机划分配额相对的另一种做法,是让所有人都用更慢的磁盘,而这正是那些标榜“SSD 存储”的超售主机通常的交付方式。我们的配额按套餐划分,公布在定价页面上,由 hypervisor 的 I/O 限流来强制执行,并且会把未使用的容量归还到资源池。实际使用中,VPS-4 在 99% 以上的时间里都能用满它的全部配额;其余时间是邻居做备份期间出现的短暂争用,表现为几百微秒(而不是几秒)的 p99 尖峰。
如果您需要去掉这个上限,独立服务器才是最实在的答案。这对镜像的 NVMe 硬盘,能把表中第一列的性能完整地交给您一个人独享,而 ZFS on root 附加选项会拿出其中大约 5% 的性能,换取校验和与快照,对于任何存放着重要数据的场景,这都是一笔划算的交易。
自己动手复现
apt install -y fio
fio --name=randread --filename=/srv/fio.test --size=16G --direct=1 --rw=randread \
--bs=4k --iodepth=1 --runtime=60 --time_based --ioengine=io_uring --group_reporting
fio --name=fsync --filename=/srv/fio.test --size=16G --direct=1 --rw=randwrite \
--bs=4k --iodepth=1 --fsync=1 --runtime=60 --time_based --ioengine=io_uring --group_reporting
请看输出中的 clat percentiles,而不是那个醒目的 IOPS 数字。测试完成后记得删除测试文件;对 VPS-1 来说,16 GB 是相当可观的一块空间。
