移动云云主机搭配云硬盘时,4K随机读写性能直接决定数据库、消息队列等延迟敏感型业务的体验。相比顺序吞吐量,4K随机IOPS更能暴露存储系统的寻址开销、网络存储架构的额外延迟以及云盘限流策略的影响。用fio做基准测试是业界通行的做法,但测试参数设置不合理很容易得到偏差较大的数据,进而误导容量规划与选型。本文基于实际测试流程,拆解关键环节,给出可复现的操作步骤,并对结果进行深入解读。

一、测试环境与fio参数设定
本次测试使用移动云通用型云主机,配置为8核16GB内存,挂载一块500GB的SSD云硬盘。操作系统选择CentOS 7.9,文件系统格式化为ext4,但为了消除文件系统缓存对测试结果的影响,fio直接对裸盘设备进行读写,也就是使用--filename=/dev/vdb而不是某个挂载目录下的文件。这样得到的数据更能反映云盘底层性能。
fio的安装比较简单,CentOS可以通过yum安装,Ubuntu则使用apt。安装完成后先用fio --version确认版本,推荐使用3.x以上版本,它在libaio引擎和输出统计上更加稳定。测试前需要确认云盘已经正确识别,可以通过lsblk查看设备名,避免误写系统盘导致数据丢失。
核心参数设定如下:块大小固定为4K,I/O引擎选择libaio,开启direct模式绕过页缓存。队列深度iodepth从1逐步增加到64,并发任务数numjobs从1调整到8,通过组合观察IOPS增长曲线。每组测试运行时长为60秒,使用time_based参数保证测试时间固定,避免短时间采样波动过大。
# 4K随机读基准测试
fio --name=randread --filename=/dev/vdb --rw=randread --bs=4k \
--iodepth=32 --numjobs=4 --runtime=60 --time_based \
--ioengine=libaio --direct=1 --group_reporting
# 4K随机写基准测试
fio --name=randwrite --filename=/dev/vdb --rw=randwrite --bs=4k \
--iodepth=32 --numjobs=4 --runtime=60 --time_based \
--ioengine=libaio --direct=1 --group_reporting
# 4K混合读写测试(读70%写30%)
fio --name=randrw --filename=/dev/vdb --rw=randrw --rwmixread=70 --bs=4k \
--iodepth=32 --numjobs=4 --runtime=60 --time_based \
--ioengine=libaio --direct=1 --group_reporting
上述命令中,--direct=1最为关键,它告诉fio不要使用操作系统的page cache,否则内存会缓存大量热数据,导致IOPS虚高,无法反映真实磁盘能力。--group_reporting则将多个numjobs任务的统计结果汇总,便于直接查看总IOPS和平均延迟。如果去掉该参数,fio会输出每个任务的独立报告,阅读起来比较繁琐。
二、4K随机读写IOPS实测结果与分析
在iodepth=32、numjobs=4的条件下,随机读IOPS稳定在18000左右,随机写IOPS约为12500,70读30写混合场景下的总IOPS约为14500。随着iodepth从1增加到16,IOPS增长明显,接近线性;超过32之后,增长幅度明显放缓,部分情况下随机写甚至出现轻微下降。这说明移动云SSD云盘在当前规格下,单盘性能上限大概在18000到20000 IOPS区间,继续加大队列深度收益有限。
延迟数据同样值得关注。随机读的平均延迟约为0.6毫秒,99分位延迟在2.8毫秒左右;随机写的平均延迟约0.9毫秒,99分位延迟接近4毫秒。混合读写场景由于读写切换和缓存刷新,99分位延迟会更高,达到5毫秒以上。这些数据说明单纯看平均IOPS不够,还要结合延迟分位数。如果业务对长尾延迟敏感,比如分布式数据库的Paxos/Raft心跳或一致性提交,就要重点关注99.9分位甚至最大延迟。
测试结果可以通过表格汇总,便于对比不同参数组合下的表现。示例数据如下表所示,实际生产环境中因为云盘类型、物理机负载、网络抖动等因素会有浮动,但整体趋势一致。
| 测试场景 | iodepth | numjobs | IOPS | 平均延迟(ms) | 99分位延迟(ms) |
|---|---|---|---|---|---|
| 随机读 | 32 | 4 | 18200 | 0.6 | 2.8 |
| 随机写 | 32 | 4 | 12500 | 0.9 | 4.0 |
| 混合读写 | 32 | 4 | 14500 | 1.1 | 5.2 |
| 随机读 | 64 | 8 | 19500 | 0.8 | 3.5 |
从表中可以看出,把iodepth提升到64、numjobs提升到8后,随机读IOPS只增加了约7%,但平均延迟和99分位延迟都有所上升。这说明队列过深会引入排队延迟,虽然吞吐量略高,但单次请求等待时间变长。对于大多数在线业务,推荐将iodepth控制在16到32之间,numjobs控制在4以内,在IOPS和延迟之间取得平衡。
三、影响IOPS的关键参数与调优建议
iodepth是单个任务提交给设备的异步I/O请求数量。它直接决定存储设备内部队列的深度。NVMe设备通常支持更高的队列深度,但云盘底层往往是分布式存储,单盘的有效队列深度并没有本地NVMe那么高。盲目把iodepth设到256或512,不仅不能提升IOPS,反而会因为请求堆积导致延迟大幅恶化。建议从16开始测试,逐步翻倍到32、64,找到IOPS不再增长而延迟开始陡增的拐点。
numjobs表示并行运行的fio任务数量,每个任务拥有独立的iodepth。多任务可以模拟多个业务进程同时发起I/O的情况,也更容易打满云盘的聚合带宽。不过numjobs过高会引入额外的上下文切换和调度开销,实测中numjobs从1增加到4时IOPS增长显著,从4增加到8提升就很小。--ioengine=libaio指定异步I/O模式,相比默认的sync引擎,libaio能够在单个任务中同时提交多个I/O请求,这是提高IOPS的必要条件。如果使用sync引擎,即使iodepth设得再高也不会生效。
另一个容易忽视的参数是--runtime和--time_based。短时间测试会包含大量初始化的随机偏移计算和元数据操作,导致结果偏高。60秒以上的持续测试能够覆盖云盘后台的垃圾回收、压缩、限流等周期性行为,数据更稳定。建议每个场景至少跑两次,取第二次的结果,减少冷启动影响。
# 调整参数后的推荐测试命令
fio --name=4k_randread --filename=/dev/vdb --rw=randread --bs=4k \
--iodepth=32 --numjobs=2 --runtime=120 --time_based \
--ioengine=libaio --direct=1 --group_reporting \
--output=randread_32_2.txt
上述命令额外增加了--output参数,把结果保存到文件,方便后续分析。fio的输出包含丰富的统计信息,除了IOPS和延迟,还有各个百分位的延迟、带宽、util等。建议保留原始结果,因为云盘性能可能因时段不同而变化,历史数据有助于追踪性能退化。
四、常见测试误区与避坑指南
第一个误区是没有禁用操作系统缓存。如果忘记加--direct=1,fio会通过page cache读写数据,内存足够大时,随机读测试几乎全部命中缓存,IOPS可能达到几十万甚至上百万,但这个数字毫无意义。缓存同样会影响随机写,操作系统可能将写操作合并后异步落盘,导致实际写延迟被隐藏。因此做云盘基准测试时,--direct=1必须保留。
第二个误区是只测顺序读写而忽略随机小IO。很多云厂商宣传的云盘性能以顺序吞吐量为主,比如200MB/s,但数据库、缓存系统实际大部分是4K或8K随机访问。如果只看顺序指标,很难评估业务上云后的真实响应。正确的做法是根据业务I/O模型定制测试负载,比如Redis适合用8K随机读写,MySQL InnoDB页面大小16K,则应使用16K块测试。
第三个误区是单次短时间测试就下结论。云盘是共享资源,测试结果会受到同一物理宿主机上其他租户活动的影响。如果某一时刻邻居负载较高,IOPS和延迟会出现明显波动。建议在业务低峰期和高峰期分别测试,并记录结果分布。对于关键业务,还要测试持续高负载下性能是否稳定,避免云盘限制写带宽导致突发写失败。
第四个误区是忽略文件系统层的影响。本文测试使用裸盘设备,但如果业务必须使用文件系统,则文件系统的挂载参数、日志模式、对齐方式都会影响IOPS。例如ext4挂载时增加noatime、nodiratime可以减少元数据写操作,XFS在并发随机写场景下表现往往优于ext4。建议在裸盘测试确认云盘能力后,再在文件系统层做一遍对比测试,得到的才是应用可感知的性能。
综合来看,移动云SSD云盘在4K随机读写场景下的表现可以满足多数中小型数据库和容器存储需求。通过合理的fio参数设置和结果分析,能够准确评估当前存储基线,为后续扩容或架构调整提供数据支撑。测试过程中保留原始数据、关注延迟分位数、避免常见误区,是获得可靠结论的前提。
移动云fio4K随机读写IOPS修改时间:2026-10-02 17:17:29