NVMe U.2全闪存标称百万IOPS,验收要看哪些指标?
“百万IOPS”不是一项脱离条件的固定能力。对美国服务器上的NVMe U.2全闪存交付,验收不能只看厂商页面或服务商截图,而要确认这组数字对应的是单块SSD、多个盘组成的阵列,还是文件系统与网络服务的综合结果;同时记录块大小、读写比例、队列深度、线程数、测试时长、延迟分位数和设备温度。
建议把验收分成五个层次:配置真实性、NVMe磁盘与PCIe链路、网络端口与路由、同口径性能测试、长时间稳定性。只有测试条件和交付配置能够一一对应,百万IOPS才具有决策价值。以下示例以Linux系统、专用测试卷和常见PCIe NVMe U.2设备为基础,具体通过标准应以合同或订单中的配置与性能条款为准。
一、先把“百万IOPS”变成可核对的指标
1. 明确被验收的对象
交付前应先写清楚测试对象,否则很容易出现“单盘规格”和“阵列结果”混用的情况。
| 验收对象 | 需要确认的内容 | 常见误区 |
|---|---|---|
| 单块NVMe U.2 SSD | 型号、容量、固件、PCIe代际、通道宽度、单盘IOPS | 用多盘阵列成绩代表单盘能力 |
| 多盘全闪存阵列 | 盘数、RAID或软件存储方式、条带大小、校验策略、可用容量 | 只报阵列总IOPS,不说明盘数和阵列类型 |
| 文件系统卷 | 文件系统、挂载参数、加密、缓存策略、测试文件大小 | 以裸设备成绩承诺应用层成绩 |
| 远程存储服务 | 客户端位置、网络端口、路由、协议、并发连接数 | 把本地盘IOPS当成远程访问IOPS |
| 网络带宽 | 端口协商速率、双向吞吐、丢包、重传、MTU | 用磁盘读写速度代替网络带宽 |
如果订单只写“NVMe U.2全闪存、百万IOPS”,验收时应要求补充至少以下条件:
- IOPS是随机读、随机写,还是混合读写。
- 块大小是4KiB、8KiB还是其他规格。
- 队列深度和并发线程数是多少。
- 测试的是单盘、整组磁盘、文件系统还是远程服务。
- 测试持续时间、预热方式、稳态要求和延迟上限。
- 是否包含网络传输、协议开销和客户端处理能力。
- “百万”是平均IOPS,还是某个短时间峰值。
2. 理解IOPS、带宽和延迟的关系
IOPS和吞吐量不是同一个指标。计算时要先确认块大小和单位。
计算公式为:
吞吐量 = IOPS × 单次I/O大小
例如,1,000,000 IOPS使用4KiB块大小时:
- 每秒传输量 = 1,000,000 × 4,096字节
- 结果为4,096,000,000字节/秒
- 按十进制换算约为4.096GB/s
- 按二进制换算约为3.815GiB/s
如果块大小改为8KiB,同样的1,000,000 IOPS就需要约8.192GB/s的介质吞吐,可能已经接近或超过单条PCIe Gen4 x4链路的实际可用能力。因此,“百万IOPS”必须和块大小一起阅读。
网络带宽则通常使用bit/s。例如10Gbps链路的理论十进制传输能力为:
- 10,000Mbps × 30秒 ÷ 8 ÷ 1000
- 30秒内理论传输量约为37.5GB
实际测试中还会受到以太网、TCP、协议、CPU和接收端处理能力影响。磁盘测试显示4GB/s,并不代表10Gbps网络就一定能以同样速度传输;反过来,10Gbps端口也不能让单块低性能磁盘达到4GB/s。
延迟也不能被IOPS覆盖。一个示例是:队列深度为256、IOPS约为1,000,000时,用“队列深度 ÷ IOPS”估算平均在途时间约为256微秒,但这只是近似关系,并不能代替p99或p99.9延迟。高队列深度下得到的百万IOPS,可能伴随较高的尾延迟,不一定适合低延迟数据库或交易型业务。
二、按交付顺序核对配置真实性
1. 先固定主机、磁盘和网络清单
验收不要从跑测试开始。先建立一份交付清单,记录服务器主机名、IP、机房或区域标识、系统版本、CPU型号、内存、NVMe数量、每块盘的序列号、容量、固件和网络端口信息。
美国服务器的物理区域应以订单、服务商控制台或交付单中的机房信息为准,IP地理定位只能作为辅助信息,不能单独作为机房位置证据。公网IP段可能被注册在其他地区,BGP路由也可能经过不同网络。
在服务器上执行以下基础检查:
date -Is
hostnamectl
uname -a
lscpu
free -h
lsblk -d -o NAME,SIZE,MODEL,SERIAL,ROTA,TRAN,TYPE
sudo nvme list
ip -br addr
ip -br link
重点查看:
lsblk中的设备是否为nvme而不是SATA或虚拟块设备。- NVMe数量是否与订单一致。
- 型号和容量是否与交付单一致。
- 序列号是否逐块记录,避免替换盘后仍沿用旧截图。
- 网络接口数量、接口名称和协商速率是否符合配置。
- 是否存在云平台或虚拟化层,导致看到的是虚拟磁盘而非直通U.2设备。
如果容量使用TB和TiB两种口径,应单独记录。厂商通常以十进制TB标注,操作系统可能以GiB或TiB显示,不能仅凭显示数值差异判定缺盘。需要结合型号标称容量、分区表、阵列预留空间和文件系统可用容量判断。
2. 确认U.2端口真正连接到PCIe NVMe链路
U.2是物理连接形式,不自动等于完整PCIe x4性能。实际链路可能受到主板插槽、背板、转接卡、PCIe交换芯片、BIOS设置或通道共享影响。
查看NVMe控制器与PCIe设备的关系:
sudo nvme list-subsys
readlink -f /sys/class/nvme/nvme0/device
BDF=$(basename "$(readlink -f /sys/class/nvme/nvme0/device)")
lspci -s "$BDF" -vv
lspci -t
在lspci -vv中重点记录:
LnkCap:设备支持的最高链路速度和宽度。LnkSta:当前实际协商的链路速度和宽度。- 是否显示PCIe错误、链路降级或设备异常。
- 设备挂在哪个CPU或PCIe根端口下。
- 是否经过PCIe交换芯片或重定时器。
常见链路标识的含义如下:
| 链路信息 | 说明 |
|---|---|
16GT/s, Width x4 | 通常对应PCIe Gen4 x4,具体仍需结合设备和主板信息 |
8GT/s, Width x4 | 通常对应PCIe Gen3 x4 |
16GT/s, Width x2 | 代际不一定低,但通道数减少,带宽和并发能力可能受影响 |
8GT/s, Width x1 | 可能是插槽、背板、BIOS分配或硬件连接异常 |
| 当前协商速率低于支持能力 | 需要检查BIOS、固件、背板、温度和链路错误 |
不要只看LnkCap。设备支持PCIe Gen4 x4,不代表当前一定以Gen4 x4运行;验收应以LnkSta的当前状态为准。

还需要确认磁盘和CPU是否位于同一个NUMA节点:
numactl -H
lscpu -e=CPU,NODE,SOCKET
cat /sys/block/nvme0n1/device/numa_node
如果NVMe挂在NUMA节点1,而fio线程和内存主要位于节点0,测试结果可能包含跨节点访问开销。多路CPU服务器应至少进行一次本地NUMA测试,并记录CPU绑定方式。否则不同测试人员在不同CPU节点启动相同命令,结果可能出现明显差异。
3. 检查磁盘健康状态和固件
执行健康检查:
sudo nvme smart-log /dev/nvme0
sudo nvme id-ctrl /dev/nvme0
sudo nvme id-ns /dev/nvme0n1
重点保存以下字段:
critical_warningtemperatureavailable_sparepercentage_useddata_units_readdata_units_writtenmedia_errorsnum_err_log_entries- 固件版本
- 型号、序列号和容量
验收时不能只看“SMART正常”。如果存在介质错误、错误日志持续增长、可用备用空间异常下降或关键警告,应先停止性能判定,确认设备状态和更换责任。
健康数据要在测试前后各采集一次。对于长时间随机写,测试后的写入量、温度和错误计数可能明显变化。若只保存测试结束时的结果,就无法判断异常是交付时已存在,还是测试过程中产生。
固件版本也应纳入验收记录。相同型号的不同固件可能在功耗、温控、队列处理和稳定性方面存在差异。更换固件前要保留原始版本、当前健康数据和业务备份;固件升级失败可能导致设备不可用,不能在生产业务卷上未经审批执行。
三、检查端口、路由和网络带宽
本地NVMe性能与公网或专线网络性能是两组独立指标。服务器本地跑出百万IOPS,并不代表远程客户端能够获得相同结果。
1. 核对接口协商状态
先确认接口名称,再查看物理协商状态:
ip -br link
sudo ethtool ens160
将ens160替换为实际接口名称。重点记录:
SpeedDuplexAuto-negotiationLink detected- 接口错误和丢包计数
- 网卡驱动和固件信息
如果订单为10Gbps,但ethtool显示1000Mb/s,需要先处理端口、模块、线缆、交换机端口或驱动问题,不能用磁盘测试结果掩盖链路降速。
可以保存接口统计:
sudo ethtool -S ens160
ip -s link show dev ens160
验收时应区分物理端口速率、TCP实际吞吐和应用有效吞吐。三者分别对应硬件链路、传输协议和业务程序,不应合并成一个“带宽值”。
2. 确认实际路由和MTU
从真实客户端向美国服务器发起测试,检查目的地址使用的源地址、网关和接口:
ip route get 203.0.113.20
tracepath -n 203.0.113.20
ping -c 20 203.0.113.20
将示例地址替换为实际测试端。ip route get可以确认本机选择的路由和出口接口;tracepath可辅助观察路径和MTU变化;ping只能反映ICMP探测结果,不能单独证明业务链路没有丢包,因为部分网络会限制或过滤ICMP。
如果服务通过固定网络、专线或内网访问,应从实际业务客户端测试,而不是只在服务器本机测试。公网路由可能因运营商、访问地区、时间段和目的IP不同而改变。
3. 用iperf3单独验证网络吞吐
iperf3主要在内存中生成和接收数据,适合将网络因素与磁盘因素分离。测试前应确认双方都有授权,并确保测试窗口不会影响其他业务。
服务端执行:
iperf3 -s
客户端执行正向和反向测试:
iperf3 -c 203.0.113.20 -P 4 -t 30 -O 5 -J > iperf3-forward.json
iperf3 -c 203.0.113.20 -P 4 -t 30 -O 5 -R -J > iperf3-reverse.json
参数含义:
-P 4使用4个并行流,避免单连接受窗口或CPU影响。-t 30持续30秒,避免只记录瞬时峰值。-O 5忽略前5秒预热阶段。-R测试反向方向。-J输出JSON,便于留档和复核。
结果需要同时查看带宽、重传、发送端和接收端速率。若正向正常、反向明显偏低,可能涉及交换机端口、路由策略、网卡队列或接收端处理能力。若iperf3正常而远程存储读写很低,应继续检查协议、客户端CPU、文件系统和存储服务,而不能直接判定NVMe故障。
四、建立可复现的NVMe性能测试
1. 测试前置条件
性能测试最好使用专用测试卷或专用目录。文件系统测试能够反映应用实际路径,但会包含文件系统、加密、挂载参数和阵列缓存开销;裸设备测试更接近设备本身,却会覆盖数据。
以下示例使用专用挂载点/mnt/nvme-test和测试文件,不直接写生产设备:
df -h /mnt/nvme-test
mkdir -p /mnt/nvme-test
fio --version
测试目录中的文件会被反复写入。使用前要确认该目录没有业务数据,并保留必要备份。不要把/dev/nvme0n1直接作为filename用于随机写,除非该命名空间已经确认为空、已完成备份、已得到变更批准,并且接受恢复或重新分区的影响。裸设备写入没有普通意义上的“撤销”,回滚通常只能依靠备份恢复或重新配置。
测试文件应足够大,避免系统页缓存影响结果。可按“至少大于内存容量的一部分、并明显大于业务工作集”的原则设置;资源有限时,64GiB可以作为示例起点,但不能对所有容量和内存配置一概而论。文件太小、测试时间太短或只跑一次,都可能得到不稳定的峰值。
开始前记录:
- CPU和内存占用。
- NVMe温度和健康计数。
- 设备当前容量使用率。
- 文件系统和挂载参数。
- 测试文件大小。
- fio版本、内核版本和ioengine。
- 是否启用NUMA绑定。
- 是否有备份任务、杀毒扫描、同步程序或其他I/O负载。
2. 随机读、随机写和混合读写
下面命令以4KiB随机读为例,测试文件只位于专用测试目录:
fio --name=randread-4k \
--filename=/mnt/nvme-test/fio.bin \
--size=64G \
--rw=randread \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=64 \
--numjobs=4 \
--runtime=60 \
--time_based \
--ramp_time=10 \
--group_reporting=1 \
--norandommap=1 \
--randrepeat=0 \
--output-format=json \
--output=/mnt/nvme-test/randread-4k.json
该配置的总在途深度大致为iodepth × numjobs,即256,但实际有效深度还会受内核、设备和fio版本影响。libaio在常见Linux环境中兼容性较好;如果系统和fio支持io_uring,也可以在保持其他条件不变的情况下单独进行对照测试,但必须记录ioengine变化,不能把两种结果直接合并。
随机写测试:
fio --name=randwrite-4k \
--filename=/mnt/nvme-test/fio.bin \
--size=64G \
--rw=randwrite \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=64 \
--numjobs=4 \
--runtime=60 \
--time_based \
--ramp_time=10 \
--group_reporting=1 \
--norandommap=1 \
--randrepeat=0 \
--output-format=json \
--output=/mnt/nvme-test/randwrite-4k.json
混合读写更接近一部分数据库、虚拟化和文件服务负载:
fio --name=randrw-4k-70read \
--filename=/mnt/nvme-test/fio.bin \
--size=64G \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=4 \
--runtime=60 \
--time_based \
--ramp_time=10 \
--group_reporting=1 \
--norandommap=1 \
--randrepeat=0 \
--output-format=json \
--output=/mnt/nvme-test/randrw-4k-70read.json
随机写会改变设备内部状态,可能触发垃圾回收、磨损均衡和缓存回收。若先跑随机写、后跑随机读,应记录测试顺序,并在两项之间安排统一的空闲冷却时间。更换顺序后重新测试,结果可能不同。
3. 顺序带宽测试
顺序读写用于判断PCIe链路、阵列聚合和大块I/O能力,不能代替随机IOPS测试。
顺序读示例:
fio --name=seqread-1m \
--filename=/mnt/nvme-test/fio.bin \
--size=64G \
--rw=read \
--bs=1M \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=1 \
--runtime=60 \
--time_based \
--ramp_time=10 \
--group_reporting=1 \
--output-format=json \
--output=/mnt/nvme-test/seqread-1m.json
顺序写示例:
fio --name=seqwrite-1m \
--filename=/mnt/nvme-test/fio.bin \
--size=64G \
--rw=write \
--bs=1M \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=1 \
--runtime=60 \
--time_based \
--ramp_time=10 \
--group_reporting=1 \
--output-format=json \
--output=/mnt/nvme-test/seqwrite-1m.json
如果顺序带宽明显低于链路和设备的合理范围,先检查PCIe当前协商宽度、NUMA位置、阵列条带、文件系统空间和温度。不要因为随机读IOPS达标,就跳过顺序读写;备份、镜像、日志归档和大文件传输通常更依赖顺序带宽。
4. 长时间稳定性测试
60秒测试适合快速验收,不足以发现持续写入后的温度变化、SLC缓存耗尽或错误计数增长。需要验证稳定性的交付,建议在业务空闲窗口进行30分钟至数小时的重复测试,时间长度以合同要求和设备容量为准。
稳定性测试至少记录:
- 每个时间段的IOPS和带宽。
- 平均延迟、p95、p99、p99.9和最大延迟。
- 每块NVMe的温度变化。
media_errors和错误日志数量。- CPU占用、软中断和I/O等待。
- 网络测试中的重传和丢包。
- 是否出现性能逐步下降或周期性抖动。
不能把“测试命令没有报错”作为稳定性的全部依据。设备可能没有返回I/O错误,但已经出现温度过高、尾延迟持续增加或吞吐周期性下降。

五、用正确方法解释测试结果
1. 先看测试条件,再看数字
一个结果只有在条件完全一致时才具有可比性。至少需要同时查看:
rw:读、写或混合模式。bs:块大小。iodepth和numjobs:队列与并发。runtime和ramp_time:持续时间与预热。direct和文件系统路径。- 单盘还是阵列。
- 测试前设备是否处于空闲、预热或稳态。
- CPU、NUMA和网络位置。
以下是用于说明判读方式的模拟结果,不代表某一具体产品的实测成绩:
| 测试场景 | 示例结果 | 可作出的判断 |
|---|---|---|
| 单盘4KiB随机读,QD总计256 | 1.03M IOPS,p99 420μs | 达到百万级随机读,但仍需确认高队列下的尾延迟 |
| 单盘4KiB随机写,QD总计256 | 0.42M IOPS,p99 780μs | 不能用随机读标称值推断随机写能力 |
| 4KiB 70/30混合,QD总计128 | 0.78M IOPS,p99 610μs | 更接近混合负载,不能称为“百万IOPS” |
| 1MiB顺序读 | 7.0GB/s | 需要结合PCIe代际、通道宽度和阵列盘数判断是否合理 |
| 1MiB顺序写,运行30分钟后下降 | 前10分钟6.2GB/s,后续3.1GB/s | 可能涉及缓存耗尽、垃圾回收、温控或稳态差异 |
第一行结果可以描述为“在4KiB随机读、总队列深度约256的条件下达到百万级IOPS”。不能改写成“任何负载下均有百万IOPS”。
2. 关注尾延迟和异常计数
IOPS高但p99、p99.9延迟高,通常意味着设备依靠较深队列堆出吞吐。对于批处理、并行扫描等负载,这可能可以接受;对于数据库提交、虚拟机系统盘或实时服务,尾延迟往往比峰值IOPS更重要。
可以使用以下判断分支:
- IOPS低、PCIe链路降为x1或x2:优先检查背板、转接卡、BIOS通道分配和物理连接。
- 顺序带宽正常、随机IOPS低:检查块大小、队列深度、线程数、文件系统和设备固件。
- 随机读达标、随机写明显低:确认产品写入规格、设备磨损状态、缓存策略和测试是否进入稳态。
- 前几分钟很快、随后下降:观察温度、缓存耗尽和垃圾回收,不要只取前段峰值。
- 平均延迟正常、p99.9异常:检查后台任务、NUMA跨节点、设备错误和网络抖动。
- 本地fio正常、远程fio偏低:优先检查路由、端口、MTU、TCP重传、协议和客户端CPU。
- 同配置重复结果差异大:先检查测试文件大小、冷却时间、后台负载和设备当前状态。
性能下限应尽量在合同中提前定义。例如,可以明确“4KiB随机读、指定队列深度和时长下,平均IOPS不低于某值,p99不高于某值,测试期间不得出现介质错误”。如果合同没有这些条件,验收记录应把本次测试条件写完整,避免后续把不同口径的数字放在一起比较。
3. 不把阵列、网络和单盘结果混为一谈
多块NVMe组成阵列后,IOPS可能随盘数增加,但阵列控制器、CPU、校验、条带大小和文件系统会带来额外开销。阵列结果还可能受最慢一块盘限制。
建议分别保存:
- 单块NVMe的设备级结果。
- 整组阵列或存储池的结果。
- 文件系统挂载路径的结果。
- 从实际客户端访问服务的结果。
- 独立iperf3网络结果。
如果交付条款只承诺整组全闪存的性能,就应把盘数、RAID级别、可用容量和测试路径写进验收单。如果条款承诺单盘性能,就不能用阵列总成绩替代。
六、出现异常时如何留证和定位
1. 保存原始命令和环境信息
截图适合辅助说明,不适合作为唯一证据。建议用终端录制和JSON结果保存完整过程:
mkdir -p "$HOME/acceptance-logs"
script -a "$HOME/acceptance-logs/session.log"
date -Is
hostnamectl
uname -a
fio --version
sudo nvme list
lsblk -d -o NAME,SIZE,MODEL,SERIAL,ROTA,TRAN,TYPE
ip -br addr
ip -br link
完成所有测试后执行:
exit
sha256sum "$HOME"/acceptance-logs/*
sha256sum /mnt/nvme-test/*.json
证据包应包含:
- 订单或交付配置。
- 主机名、IP和区域信息。
- NVMe型号、序列号、容量和固件。
- PCIe
LnkCap、LnkSta和拓扑。 - 测试前后的健康日志。
- fio完整JSON或文本输出。
- CPU、NUMA、系统版本和fio版本。
- 网卡协商状态、路由和iperf3结果。
- 测试开始结束时间、测试顺序和冷却时间。
- 异常发生时的温度、错误计数和后台负载。
序列号和公网IP在公开发布时可以脱敏,但内部验收记录应保留完整值,以便追溯具体设备。
2. 异常时不要覆盖第一次结果
发现异常后,不要立即重启、更换固件、重新格式化或删除测试日志。先保存现场,再按影响范围进行复测:
- 如果链路宽度不符,保留
lspci -vv、主板或背板信息,要求服务商先核对硬件连接。 - 如果健康计数异常,保存前后两次
nvme smart-log,暂停高强度写入。 - 如果温度升高后性能下降,记录温度曲线和每轮fio结果,再检查风道、风扇、散热片和温控策略。
- 如果网络吞吐低,分别保存
ethtool、ip route get、iperf3双向结果和客户端信息。 - 如果只有文件系统路径异常,使用同一测试文件和参数对比专用卷、阵列卷或其他挂载点。
- 如果只有某一块盘异常,不能用其他盘的平均值冲淡问题,应按序列号单独追踪。
七、复测时保持条件不变
复测不是重新运行一条命令这么简单。以下条件变化都可能改变结果:
- PCIe代际或链路宽度。
- 固件、BIOS、内核或fio版本。
- 测试文件大小和文件系统。
ioengine、块大小、队列深度、线程数。- CPU亲和性和NUMA节点。
- 测试顺序、预热时间和冷却时间。
- 磁盘使用率、磨损程度和缓存状态。
- 网络客户端、源地址、路由、MTU和并发连接数。
- 是否存在备份、同步、监控扫描或其他I/O任务。
建议使用同一台客户端、同一块测试卷、同一组参数,在相同时间窗口完成复测。每项至少重复三次,并记录平均值、最好值、最差值和离散程度。若合同没有规定重复次数,可以把“同条件三次结果最大差异不超过约10%”作为内部复核参考,但不应把这个示例阈值当成所有设备的统一标准。
复测前后重新采集设备健康信息和链路状态。只有在“配置一致、链路正确、健康无异常、测试口径一致、性能达到约定下限、长时间运行无错误”的条件同时满足时,才适合在验收单上确认百万IOPS或其他性能指标。
最终留存的不是一张显示“1.0M IOPS”的截图,而是一套可复核的交付证据:设备身份对应哪块盘,当前PCIe端口是什么状态,测试使用了什么参数,结果包含多少IOPS、带宽和尾延迟,网络从哪个客户端经过什么路径,长时间运行是否出现降速或错误,以及异常后的复测是否仍能得到相同结论。



