上一篇 下一篇 分享链接 返回 返回顶部

美国服务器NVMe U.2全闪存随机读写百万IOPS如何测试验证

发布人:Minchunlin 发布时间:2026-10-06 08:44 阅读量:8

“百万IOPS”容易被误读成“所有请求都能快速完成”。实际上,它通常描述特定块大小、读写比例和并发深度下,每秒完成的I/O数量,不代表低并发性能,也不代表数据库事务数。验证美国服务器上的NVMe U.2全闪存是否达到百万随机读写IOPS,需要分别测试随机读、随机写和混合读写,同时检查尾延迟、CPU负载、温度以及持续运行后的波动。

测试应在独占或资源边界明确的服务器上进行,使用经过确认的专用测试卷,记录SSD数量、PCIe链路、存储拓扑和软件版本。下文提供Linux与fio的文件级测试方法,不预设任何实测结论;最终判断应以同一条件下的重复测试、业务延迟要求和交付验收口径为依据。

一、测试目标:把“百万IOPS”变成可验证的条件

明确测的是单盘、阵列还是整台服务器

U.2描述的是设备形态与连接方式,不能仅凭“NVMe U.2”推断性能。控制器、NAND类型、容量、固件、PCIe代际和通道数,都可能影响测试结果。

“全闪存”也不等于多块SSD能够按数量线性叠加。测试前至少要区分三种对象:

测试对象能回答的问题不能直接推出的结论
单块NVMe SSD单盘在指定负载下的性能多盘阵列或业务卷一定达到同等倍数
多盘独立并行访问各盘并行运行时的服务器聚合能力一个数据库文件能够利用全部性能
RAID、逻辑卷或存储池交付存储路径的实际性能阵列内每块盘都没有瓶颈

如果四块SSD同时运行后合计超过百万IOPS,应表述为“四盘聚合性能”,不能写成“单盘百万IOPS”。如果业务使用的是带冗余的阵列,应在该阵列上测试,不能用无冗余条带卷的结果替代交付性能。

分开验收随机读、随机写和混合负载

建议把测试目标写成以下形式:

在指定服务器、指定存储卷上,采用4KiB随机访问、直接I/O、明确的并发配置,分别测量纯读、纯写和70%读/30%写负载。预热后持续采样,记录IOPS、吞吐、平均延迟、P99、P99.9、CPU占用及温度,并重复至少三轮。

这里的4KiB和70/30只是参考配置,不是所有业务的统一标准。数据库可能更关注8KiB或16KiB访问,日志系统可能更关注追加写和同步写,文件下载则更关注大块顺序吞吐。

对于A5IDC美国服务器的性能验收,还应把本地存储性能与网络访问体验分开。在服务器内部运行fio,可以减少跨地区网络因素的干扰;从国内客户端访问美国服务器测到的响应时间,则同时包含网络往返、应用处理和存储耗时,不能直接作为SSD延迟。

二、指标含义:IOPS必须与延迟、吞吐一起看

IOPS与吞吐之间有明确的换算关系

固定块大小时:

吞吐量 = IOPS × 每次I/O的字节数。

以100万IOPS、每次4KiB为例:

  • 4KiB = 4096字节。
  • 100万 × 4096 = 4,096,000,000字节/秒。
  • 按十进制口径约为4.096GB/s。
  • 按二进制口径约为3.815GiB/s。

因此,4KiB百万IOPS不仅要求SSD处理大量请求,也要求PCIe链路、阵列软件和CPU能够承受约4.1GB/s的数据流动。若结果中的IOPS与带宽明显不匹配,首先检查块大小、单位以及读写汇总方式。

对于70/30混合负载,应报告读IOPS、写IOPS和两者之和。不能把“读70万、写30万”表达为“随机读和随机写分别达到百万”。

平均延迟解释效率,尾延迟解释卡顿

平均延迟能够反映整体效率,但少量慢请求可能被平均值掩盖。交付验收至少应保留:

指标主要用途解读注意事项
平均延迟判断整体处理效率不能替代尾延迟
P95观察大部分请求的响应情况适合常规性能对比
P99、P99.9识别长尾与突发停顿对数据库和在线接口更重要
时间序列IOPS检查持续性和周期性波动全程平均值可能掩盖短时跌落
错误、超时和重试判断结果是否可用于验收高IOPS不能抵消I/O错误

fio输出中的slat是提交延迟,clat是提交完成后到I/O完成的延迟,lat是总延迟。比较报告时必须使用相同口径,并留意输出单位是纳秒、微秒还是毫秒。

多个作业的P99不能简单求平均,更不能把不同时间段的P99平均后当作全程P99。需要用合并后的延迟分布计算,或者直接使用统一测试报告中的聚合统计。

高并发能提高IOPS,也可能推高延迟

在系统稳定、统计边界一致时,可以用下面的关系辅助判断:

平均在途I/O数量 ≈ IOPS × 平均响应时间。

例如,总在途I/O约为256、IOPS约为100万时,对应的平均响应时间约为256微秒。这个关系不能推出P99,也不能保证实际队列始终满载,但能帮助判断数量级是否合理。

因此,提高队列深度后突破百万IOPS,并不自动说明服务更快。若业务只有少量并发请求,高队列测试结果可能很难转化为实际收益。

三、影响变量:先确认测试走的是哪条存储路径

核对设备、挂载和软件版本

以下检查命令适用于具备相应工具的Linux环境,主要用于读取信息,不会主动写入测试盘。缺少工具时,应按实际发行版安装,不能假定不同系统使用相同的软件包命令。

uname -r
fio --version

lsblk -o NAME,TYPE,SIZE,MODEL,SERIAL,FSTYPE,MOUNTPOINTS
findmnt -T /mnt/nvme-bench

nvme list
lspci -D | grep -Ei 'non-volatile|nvme'

/mnt/nvme-bench在本文中代表提前准备好的专用测试卷挂载点,使用前必须替换为实际路径。部分旧版lsblk不支持MOUNTPOINTS,可通过lsblk --help核验,必要时改用MOUNTPOINT。

验收记录至少应包含:

  • CPU型号、核心数、NUMA布局和内存容量。
  • SSD型号、容量、数量、固件和当前健康状态。
  • PCIe协商速率、链路宽度,以及多盘是否共享上行链路。
  • 文件系统、阵列方式、挂载参数和测试卷剩余空间。
  • 内核、fio版本、I/O引擎及服务器是否独占。
  • 是否存在数据库、备份、快照、重建或其他后台I/O。

若需要检查PCIe链路,应先从lspci -D获得对应设备地址,再执行:

lspci -s 0000:xx:yy.z -vv

将示例地址替换为真实地址,关注LnkCap和LnkSta。设备支持的速率与当前协商速率不一定相同;权限不足时,输出也可能不完整。

排除缓存和测试区域过小造成的误判

Linux文件级测试应使用direct=1,尽量绕过主机页缓存。否则,内存可能承担大量读请求,结果并不能代表SSD性能。

但直接I/O仍然经过文件系统和块层,也不能绕过SSD内部缓存。测试区域过小、数据刚写完就读取、写入数据过于容易压缩,都可能让结果偏离长期业务负载。

以主机和NVMe SSD为两个明确区域,突出fio文件级直接I/O经过文件系统、块层进入SSD的路径;主机页缓存位于路径旁并标注绕过,SSD内部缓存保留在设备区

建议记录“实际访问数据量占卷容量的比例”。本文示例使用四个32GiB文件,总访问范围为128GiB,这是可执行的起点,不是充分的稳态条件。如果测试的是数TB存储卷,128GiB可能仍然偏小,应根据剩余空间、业务数据规模和写入预算扩大范围。

新盘状态与持续写入状态要分开

SSD在空闲空间充足时,短时间写入可能较快;随着缓存消耗、垃圾回收和后台整理发生,持续随机写性能可能变化。不能拿新盘前一分钟的高值代替长期能力。

稳态测试应采用明确的预处理和观察窗口。对于验收,可约定连续若干窗口中IOPS与P99的变化不超过某个容差,再比较稳定阶段的数据。容差应由用途决定,而不是把某个百分比视为通用标准。

全盘填充和长时间随机写会增加介质写入量,必须在维护窗口内、专用测试设备上进行,并事先确认写入预算。不要为追求“充分预热”而直接覆盖生产盘。

四、测试方法:先准备数据,再做并发扫描

建立安全的测试目录和数据文件

随机写测试会覆盖测试文件内容,并消耗SSD写入寿命。执行前应完成重要数据备份,确认卷上没有生产数据,暂停会竞争该卷的业务。测试负载也可能影响同机其他服务,因此最好安排维护窗口。

以下示例使用Bash,在已经挂载的专用卷内创建独立目录。它不会格式化设备,也不会主动写入裸盘:

mountpoint -q /mnt/nvme-bench || {
  echo "专用测试卷未挂载,停止测试"
  exit 1
}

df -h /mnt/nvme-bench
export BENCHDIR
BENCHDIR=$(mktemp -d /mnt/nvme-bench/fio-test.XXXXXX) || exit 1
printf '测试目录:%s\n' "$BENCHDIR"

fio --name=prepare \
  --directory="$BENCHDIR" \
  '--filename_format=bench.$jobnum' \
  --ioengine=libaio --direct=1 \
  --rw=write --bs=1M \
  --numjobs=4 --iodepth=32 --size=32G \
  --refill_buffers=1 --end_fsync=1 \
  --group_reporting \
  --output-format=json \
  --output="$BENCHDIR/prepare.json"

这里四个作业分别使用自己的文件,避免多个作业反复覆盖同一组数据。fio中的32G按二进制单位表示32GiB,四个文件合计128GiB;可用空间还应留出文件系统和结果日志余量。

应先检查prepare.json中的错误信息,确认准备成功,再继续测试。预写用于建立有效数据文件,不等于SSD已经进入长期随机写稳态。

本方法的影响范围是新建测试目录内的文件。正常退出fio即可停止负载,清理时只处理已经核对的该目录。如果误把路径指向了生产文件,覆盖的数据不能靠“回滚命令”恢复,只能依赖备份;因此不建议直接套用裸设备写入命令。

用相同配置扫描不同队列深度

下面定义一组公共参数,方便保持比较口径一致:

FIO_ARGS=(
  --name=u2-bench
  --directory="$BENCHDIR"
  '--filename_format=bench.$jobnum'
  --ioengine=libaio
  --direct=1
  --bs=4k
  --size=32G
  --numjobs=4
  --time_based=1
  --runtime=180
  --ramp_time=30
  --randrepeat=0
  --allow_file_create=0
  --group_reporting=1
  --lat_percentiles=1
  --percentile_list=50:95:99:99.9
)

这组参数表示:每轮先预热30秒,再统计180秒;四个作业各访问32GiB文件。allow_file_create=0用于防止正式测试时因路径错误而创建新数据文件。参数支持情况应以本机fio --help或fio --cmdhelp=参数名为准。

随机读可先扫描每个作业的队列深度1、8、32、64,并重复三轮:

for round in 1 2 3; do
  for qd in 1 8 32 64; do
    fio "${FIO_ARGS[@]}" \
      --readonly --rw=randread --iodepth="$qd" \
      --write_iops_log="$BENCHDIR/read-r${round}-qd${qd}" \
      --log_avg_msec=1000 \
      --output-format=json \
      --output="$BENCHDIR/read-r${round}-qd${qd}.json"
  done
done

四个作业、每个作业iodepth=64,理论配置上限为256个在途I/O,而不是64。实际达到的深度还应检查fio报告中的队列深度分布。

这组完整扫描约需42分钟,不含准备和间歇时间。可以先做一轮寻找拐点,再对拐点附近配置重复采样。如果业务关注单请求延迟,应额外运行numjobs=1、iodepth=1,不能用四作业结果代替。

随机写与混合读写单独测试

确认文件范围和写入预算后,可在同一组数据文件上执行:

fio "${FIO_ARGS[@]}" \
  --rw=randwrite --iodepth=64 --refill_buffers=1 \
  --write_iops_log="$BENCHDIR/write-qd64" \
  --log_avg_msec=1000 \
  --output-format=json \
  --output="$BENCHDIR/write-qd64.json"

fio "${FIO_ARGS[@]}" \
  --rw=randrw --rwmixread=70 --iodepth=64 \
  --refill_buffers=1 \
  --write_iops_log="$BENCHDIR/mix70-qd64" \
  --log_avg_msec=1000 \
  --output-format=json \
  --output="$BENCHDIR/mix70-qd64.json"

这两条命令展示的是单轮方法,正式比较仍需扫描相关队列深度并重复测试。读写比例是提交负载的配置,结果中仍要检查实际完成的读写数量。

refill_buffers=1用于降低重复写入相同内容造成的偏差,但也会增加CPU工作量,应在不同测试组中保持一致。

需要特别区分:直接I/O写入完成,不等于数据库事务已经满足持久化要求。需要逐次同步、日志落盘或断电一致性的业务,应另测对应的同步写负载,并确认设备写缓存、flush语义和掉电保护条件,不能直接引用普通随机写IOPS。

同步采集CPU、设备和温度

fio只说明负载完成情况,系统监控用于解释原因。可在另一个终端同步运行:

iostat -x 1
mpstat -P ALL 1
pidstat -C fio -t -u 1

这些命令通常由sysstat提供。NVMe温度、健康状态和写入统计可针对确认过的设备读取:

nvme smart-log /dev/nvme0

重点看单核CPU是否饱和、各盘I/O是否均衡、温度是否上升以及是否出现降频迹象。NVMe具有并行队列,不能仅凭iostat中的%util接近100%就断定性能已经耗尽。

每秒IOPS日志适合识别波动,但每秒平均延迟不能重建每秒P99。若需要分析尾延迟随时间的变化,应使用fio延迟直方图日志,并采用与版本匹配的工具解析。

五、结果解释:突破百万与适合业务是两件事

用并发曲线识别性能拐点

下面是一组用于解释方法的示例数据,不代表某台服务器的实测结果。负载为4KiB随机读、四个作业:

每作业队列深度总配置深度上限IOPS平均延迟P99
147.5万53微秒120微秒
83242万76微秒210微秒
3212891万141微秒480微秒
64256108万237微秒1.2毫秒

这组数据说明:加深队列能提高IOPS,但最后一档的吞吐收益缩小,P99却明显增加。如果业务要求P99不超过0.5毫秒,91万IOPS对应的配置可能比108万更有价值。

五、结果解释:突破百万与适合业务是两件事/用并发曲线识别性能拐点配图

因此,报告应同时给出“峰值能力”和“满足延迟目标时的可用能力”。单独展示最高IOPS,会丢失产品选择所需的关键边界。

将性能现象与资源指标对应

观察到的现象可能原因下一步核对
IOPS不再增加,某个CPU核心接近满载提交、完成处理或软件路径受限作业分布、IRQ、NUMA位置
多盘性能不均衡数据分布、链路或单盘状态不同每盘流量、链路宽度、健康信息
随机写开始快,随后持续下降缓存耗尽、垃圾回收或空闲空间不足写入时长、填充率、预处理状态
温度上升后性能下降散热或功耗管理影响温度趋势、降频记录、机箱风道
平均IOPS正常,P99周期性升高后台任务或资源争抢备份、快照、阵列重建、宿主机竞争

这些是排查方向,不是仅凭一张图就能成立的结论。每次复测最好只改变一个因素,避免同时调整并发、文件系统和CPU绑定后无法判断原因。

不把不同采样口径混在一起

正式报告应列出每轮结果,并区分最佳值、中位值和波动范围。不能只保留最快的一轮,也不能把预热阶段的短时峰值当作持续性能。

建议同时记录:

  • 稳定采样段的整体IOPS和P99/P99.9。
  • 每秒IOPS曲线,以及低谷是否伴随温度、CPU或后台任务变化。
  • 各轮之间的差异和所有I/O错误。
  • 同一条件下的读、写、混合负载结果。

纯读突破百万,只能证明该纯读条件下达到目标;随机写或混合负载没有达到时,应分别如实描述。

六、决策边界:怎样用于选型、交付和复测

用业务延迟目标确定可用容量

“百万IOPS”适合描述服务器处理大量小块并发I/O的能力,但不直接等于百万数据库查询,也不等于百万次网页请求。一次业务操作可能触发多个I/O,也可能完全命中内存。

选型时,应先找到满足业务P99目标的稳定IOPS,再保留运维余量。例如,某配置在延迟合格条件下可持续提供80万IOPS,若内部规划采用70%的利用率预算,则规划值为56万IOPS。这个比例只是示例,实际还要考虑突发流量、备份、重建和故障时的性能下降。

如果访问的是远程存储,网络也是边界。4KiB百万IOPS对应约4.096GB/s,折合32.768Gb/s的纯数据量,尚未计入协议开销。因此,单条25Gb/s链路无法承载同等规模的有效数据流;换成更高速链路也仍需验证端到端性能。

交付报告必须能被重新运行

面向产品验收,建议保留以下材料:

  1. 服务器、SSD、存储拓扑和软件版本清单。
  2. 测试文件范围、卷填充率及预处理说明。
  3. 完整fio参数、原始JSON和时间序列日志。
  4. CPU、每盘I/O、温度及健康状态记录。
  5. 每轮结果、异常说明和最终采用的性能口径。

若测试对象是虚拟机,还应说明vCPU数量、资源共享情况、虚拟磁盘限速和存储呈现方式。来宾系统看到NVMe设备,并不足以证明底层SSD为独占直通。

哪些变化需要重新测试

更换SSD型号或容量、升级固件或内核、改变RAID与文件系统、调整虚拟化资源、PCIe链路降级,以及业务从纯读转为大量随机写,都应触发复测。数据填充率显著上升、P99持续恶化或温度条件变化,也值得重新检查。

是否达成“百万IOPS”,应落在完整条件上:指定块大小、读写比例、存储路径、并发配置和持续采样窗口内,结果可重复、无I/O错误,并同时满足约定的尾延迟要求。对于美国服务器NVMe U.2全闪存产品,这样的报告才能用于交付验收和容量规划,而不只是展示一个脱离使用条件的峰值。