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

香港服务器运行Rocky Linux 9.5,NVMe SSD的IOPS提升如何验证?

发布人:Minchunlin 发布时间:2026-10-06 10:41 阅读量:18

香港服务器上的 NVMe SSD 是否真的有 IOPS 提升,不能只看产品名称、/dev/nvme0n1 设备名或一次 fio 峰值。更可靠的验证方式,是在 Rocky Linux 9.5 环境中固定测试文件、块大小、并发度和运行时间,先建立基线,再一次只改变一个变量,连续采样 IOPS、吞吐、平均延迟和 P99 延迟。

如果比较的是两种存储方案,也不能在更换硬盘的同时改变 vCPU、内存、文件系统、内核或测试时段。下面的流程以香港服务器本机测试为主,示例数据仅用于演示如何判断,不代表某一台A5IDC服务器的实际测量结果。

先明确“IOPS提升”要验证什么

IOPS、吞吐与延迟不是同一个指标

IOPS表示每秒完成的I/O操作数量。对于小块随机读写,IOPS通常是主要指标;对于备份、视频、镜像分发等连续读写任务,吞吐量更有参考价值。

常用换算关系如下:

  • IOPS = 每秒完成的I/O操作数量
  • 十进制MB/s = IOPS × 每次I/O字节数 ÷ 1,000,000
  • 二进制MiB/s = IOPS × 每次I/O字节数 ÷ 1,048,576
  • 4KiB I/O中的4KiB通常按4096字节计算

例如,4KiB随机读达到398,000 IOPS时:

398,000 × 4,096 ÷ 1,000,000 ≈ 1,630.2 MB/s

换算为二进制单位约为:

398,000 × 4,096 ÷ 1,048,576 ≈ 1,554.7 MiB/s

因此,不能把“398,000 IOPS”直接理解为“398,000 MB/s”。两者的块大小和单位完全不同。

延迟还需要单独观察:

指标含义适合回答的问题
IOPS每秒完成的I/O数量存储系统能处理多少小块请求
BW或吞吐每秒传输的数据量连续读写或大块I/O速度如何
平均延迟所有请求的平均完成时间常态响应速度如何
P9595%的请求延迟不高于该值大多数请求是否稳定
P9999%的请求延迟不高于该值尾延迟是否明显抖动
CPU占用测试期间处理I/O所消耗的CPU是否由CPU或并发线程限制
iostat中的await块设备层观察到的等待时间内核块层是否出现排队

对于数据库、缓存、消息队列等应用,只看IOPS容易误判。例如某个配置将IOPS从40万提升到48万,但P99延迟从220微秒升到900微秒,那么它可能更适合批量吞吐,不一定适合延迟敏感的在线事务。

“提升”必须有对照组

验证提升至少需要两个状态:

  • A状态:基线配置,例如当前香港服务器的默认磁盘和系统环境。
  • B状态:只改变一个变量,例如更换存储方案、调整队列深度或改变文件系统。
  • A、B状态使用相同的测试文件大小、块大小、读写比例、运行时长和采样次数。

相对提升率可以按下面的方式计算:

提升率 =(B状态中位数 - A状态中位数)÷ A状态中位数 × 100%

例如,A状态中位数为398,000 IOPS,B状态中位数为476,000 IOPS:

(476,000 - 398,000)÷ 398,000 × 100% ≈ 19.6%

这个结果只能说明在指定测试条件下,B状态的IOPS中位数高约19.6%。它不能直接推导出所有应用都能提升19.6%,也不能说明连续读写、同步写入或远程访问一定有相同比例的变化。

在Rocky Linux 9.5上建立基线

记录系统、内核和存储设备状态

Rocky Linux 9.5属于RHEL兼容环境,但实际运行的内核、微码、NVMe驱动、文件系统和软件包状态仍然需要单独记录。相同的Rocky Linux小版本,如果安装过不同时间的更新,实际内核也可能不同。

可以先执行以下命令保存环境信息:

cat /etc/rocky-release
cat /etc/os-release
uname -r
rpm -q kernel fio nvme-cli sysstat libaio
lsblk -e7 -o NAME,MODEL,SERIAL,SIZE,ROTA,TYPE,FSTYPE,MOUNTPOINTS
findmnt -T /data
df -hT /data
fio --version
fio --enghelp | grep -E 'libaio|io_uring'

其中/data替换为实际测试盘的挂载路径。需要重点记录:

  • Rocky Linux发行版版本和具体内核版本;
  • vCPU数量、内存容量和实例规格;
  • NVMe设备名称、容量、型号和命名空间;
  • 文件系统类型,例如XFS或ext4;
  • 挂载参数,例如是否使用noatime;
  • fio版本和可用的I/O引擎;
  • 测试盘是本地盘、虚拟NVMe设备还是云平台块存储。

/dev/nvme0n1只说明系统把设备识别为NVMe命名空间,并不能单凭设备名证明它一定是物理直通盘。虚拟化平台可能将共享后端存储以NVMe形式呈现,最终性能还可能受到宿主机、存储策略或套餐IOPS上限影响。

如果系统提供nvme-cli,可以补充查看控制器信息:

sudo nvme list
sudo nvme list-subsys
sudo nvme id-ctrl /dev/nvme0
sudo nvme smart-log /dev/nvme0

虚拟设备有时不开放完整的控制器信息,smart-log执行失败不一定代表磁盘性能异常。此时应以平台提供的设备类型、IOPS上限和吞吐限制为准,并在测试记录中注明无法读取硬件健康信息。

安装测试工具时不要改变测试环境

如果系统缺少测试工具,可以在正式采样前一次性安装:

sudo dnf install -y fio nvme-cli sysstat

安装软件本身不会改变磁盘性能结论,但不要在A、B两轮测试之间执行dnf update、更换内核或升级fio。如果确实需要更新,应在更新并重启后重新建立基线。

测试期间还应记录是否有以下后台任务:

systemctl list-timers --all
ps -eo pid,comm,%cpu,%mem,stat --sort=-%cpu | head -n 20

备份、日志压缩、数据库维护、镜像同步和自动更新都可能造成存储抖动。不要为了测试而盲目停止生产服务、关闭安全策略或修改防火墙;如果服务器承载业务,应优先使用独立测试盘或业务低峰期。

使用测试文件而不是生产数据盘

文件级测试更接近应用实际访问方式,也比直接对原始块设备进行测试更安全。先创建专用目录:

sudo mkdir -p /data/fio-test
sudo chown "$USER":"$USER" /data/fio-test

/data/fio-test/benchfile必须是专门用于测试的文件。后续随机写入会覆盖该文件内容,因此应确认目录中没有业务文件,并保证测试盘有足够空间。

首次建立测试文件时,可以使用一次顺序写入预分配测试区域:

fio --name=prepare \
  --filename=/data/fio-test/benchfile \
  --rw=write \
  --bs=1M \
  --size=32G \
  --ioengine=libaio \
  --direct=1 \
  --iodepth=16 \
  --numjobs=1 \
  --end_fsync=1 \
  --group_reporting=1

这里的32G只是演示值。实际容量不足时可以调整,但测试文件不能小到完全落在内存缓存或只覆盖极小的存储范围。准备阶段不计入性能结果,后续测试只读取或改写这个专用文件。

不要直接把fio的--filename指向正在使用的/dev/nvme0n1。原始设备测试可能覆盖分区表、文件系统和业务数据。如果必须进行原始设备测试,应使用独立空盘,先完成备份和恢复演练,并由操作者确认设备路径;测试结束后的恢复通常需要重新创建文件系统或从备份恢复数据。

用固定参数完成第一轮基线

选择一个可复现的4KiB随机读配置

下面是一组适合观察小块随机读能力的基线参数:

fio --name=baseline-randread \
  --filename=/data/fio-test/benchfile \
  --rw=randread \
  --bs=4k \
  --size=32G \
  --ioengine=libaio \
  --direct=1 \
  --iodepth=8 \
  --numjobs=1 \
  --runtime=60 \
  --ramp_time=20 \
  --time_based=1 \
  --group_reporting=1 \
  --randrepeat=1 \
  --norandommap=1 \
  --lat_percentiles=1 \
  --percentile_list=50:95:99:99.9 \
  --output-format=normal

这组参数的含义是:

  • --rw=randread:执行随机读,不混入写入;
  • --bs=4k:每次I/O为4KiB;
  • --direct=1:尽量绕过操作系统页缓存,减少内存缓存的干扰;
  • --iodepth=8:单个作业最多保持8个异步I/O请求;
  • --numjobs=1:只使用一个fio作业,便于先观察单线程队列深度;
  • --ramp_time=20:前20秒作为预热,不计入正式统计;
  • --runtime=60:预热后正式采样60秒;
  • --lat_percentiles:输出延迟分位数;
  • --randrepeat=1和--norandommap=1:让随机访问模式更容易重复。

libaio是否可用应以fio --enghelp的结果为准。如果系统没有该引擎,可以记录后改用可用的异步引擎,但A、B两组必须使用同一个引擎。不能一组使用libaio,另一组使用io_uring,然后把差异全部归因于NVMe存储。

建议先执行一次预热,再连续完成5次正式采样。可以使用以下方式保存JSON结果:

for n in 1 2 3 4 5; do
  fio --name=baseline-randread \
    --filename=/data/fio-test/benchfile \
    --rw=randread \
    --bs=4k \
    --size=32G \
    --ioengine=libaio \
    --direct=1 \
    --iodepth=8 \
    --numjobs=1 \
    --runtime=60 \
    --ramp_time=20 \
    --time_based=1 \
    --group_reporting=1 \
    --randrepeat=1 \
    --norandommap=1 \
    --lat_percentiles=1 \
    --percentile_list=50:95:99:99.9 \
    --output-format=json \
    --output="baseline-${n}.json"
  sleep 10
done

每次运行都要保留原始结果,不要只记录最高的一次。5次结果可以计算中位数、最小值、最大值和变异范围。若其中一次受到备份任务、CPU抢占或系统异常影响,应在记录中保留,而不是直接删除;可以另外标注该次采样不适合用于主判断。

同时采集CPU和块设备层数据

fio反映的是应用测试进程看到的结果,iostat和mpstat可以帮助判断瓶颈位于存储、CPU还是虚拟化层。可以在另一个终端执行:

iostat -xz 1 85 > iostat-baseline.log
mpstat -P ALL 1 85 > mpstat-baseline.log
vmstat 1 85 > vmstat-baseline.log

需要关注以下现象:

  • CPU接近满载,IOPS随着并发增加却不再上升,可能是测试线程或协议栈达到瓶颈;
  • 虚拟机的vmstat中st明显升高,可能存在宿主机CPU争用;
  • iostat中的队列长度持续增加,但IOPS增长很小,说明设备或后端存储可能已经饱和;
  • fio的P99明显升高,而平均延迟变化不大,说明少量请求出现长尾;
  • NVMe温度随连续写入持续升高,后续轮次性能下降时要考虑热降速。

fio中的完成延迟和iostat中的await不处于完全相同的观测层,不能直接当作同一个数值比较。前者更接近fio请求的完成时间,后者包含块设备层排队和处理时间。

每一轮只改变一个关键变量

变量一:队列深度

队列深度是最容易造成“IOPS提升”错觉的因素之一。很多NVMe设备在低队列深度下并未达到自身吞吐能力,增加队列后IOPS会明显上升,但延迟也可能同步增加。

保持基线中的读写类型、块大小、文件、运行时间和作业数量不变,只改变iodepth:

for qd in 1 4 8 16 32; do
  fio --name="qd-${qd}" \
    --filename=/data/fio-test/benchfile \
    --rw=randread \
    --bs=4k \
    --size=32G \
    --ioengine=libaio \
    --direct=1 \
    --iodepth="$qd" \
    --numjobs=1 \
    --runtime=60 \
    --ramp_time=20 \
    --time_based=1 \
    --group_reporting=1 \
    --randrepeat=1 \
    --norandommap=1 \
    --lat_percentiles=1 \
    --percentile_list=50:95:99:99.9 \
    --output-format=json \
    --output="qd-${qd}.json"
done

以下数据是用于解释判断方式的模拟示例:

每作业队列深度IOPS平均完成延迟P99延迟CPU占用
1118,00062微秒96微秒8%
4302,00089微秒152微秒18%
8398,000117微秒212微秒34%
16472,000176微秒390微秒57%
32480,000310微秒880微秒86%

这个示例中,队列深度从8提升到16后,IOPS增加约18.6%,但P99延迟也明显升高;从16增加到32时,IOPS只增加约1.7%,P99却继续上升。更合理的解释是存储已经接近饱和,而不是“队列越大越好”。

每一轮只改变一个关键变量 / 变量一:队列深度配图

如果实际应用只有队列深度1至4,那么应重点参考低队列结果。拿队列深度32的峰值与业务队列深度1的结果比较,会夸大NVMe对真实应用的帮助。

变量二:读写类型和读写比例

随机读、随机写以及混合读写属于不同工作负载,不能用一个结果替代另一个结果。完成随机读基线后,可以分别进行随机写和混合读写测试。

随机写测试会改变测试文件内容,因此必须确认使用的是专用测试文件:

fio --name=randwrite-4k \
  --filename=/data/fio-test/benchfile \
  --rw=randwrite \
  --bs=4k \
  --size=32G \
  --ioengine=libaio \
  --direct=1 \
  --iodepth=8 \
  --numjobs=1 \
  --runtime=60 \
  --ramp_time=20 \
  --time_based=1 \
  --group_reporting=1 \
  --randrepeat=1 \
  --norandommap=1 \
  --lat_percentiles=1 \
  --percentile_list=50:95:99:99.9 \
  --output-format=json \
  --output=randwrite-4k.json

混合读写则使用randrw和rwmixread指定读比例:

fio --name=randrw-70read \
  --filename=/data/fio-test/benchfile \
  --rw=randrw \
  --rwmixread=70 \
  --bs=4k \
  --size=32G \
  --ioengine=libaio \
  --direct=1 \
  --iodepth=8 \
  --numjobs=1 \
  --runtime=60 \
  --ramp_time=20 \
  --time_based=1 \
  --group_reporting=1 \
  --randrepeat=1 \
  --norandommap=1 \
  --lat_percentiles=1 \
  --percentile_list=50:95:99:99.9 \
  --output-format=json \
  --output=randrw-70read.json

不要把随机写的IOPS和随机读的IOPS直接相加,也不要用70%读、30%写的结果代表纯读业务。数据库、日志和缓存系统的同步策略不同,写入结果尤其容易受到设备缓存、文件系统和fsync行为影响。

变量三:同步写入与普通直接写入

--direct=1只说明测试绕过了页缓存,不等于每次写入都已经持久化到介质。对于需要确认落盘时间的应用,还应单独测试同步写入。

例如,可以使用单队列、4KiB写入和每次写入同步的配置:

fio --name=sync-write-4k \
  --filename=/data/fio-test/benchfile \
  --rw=randwrite \
  --bs=4k \
  --size=32G \
  --ioengine=libaio \
  --direct=1 \
  --iodepth=1 \
  --numjobs=1 \
  --fsync=1 \
  --runtime=60 \
  --ramp_time=20 \
  --time_based=1 \
  --group_reporting=1 \
  --randrepeat=1 \
  --norandommap=1 \
  --lat_percentiles=1 \
  --percentile_list=50:95:99:99.9 \
  --output-format=json \
  --output=sync-write-4k.json

这一轮不能和普通随机写的结果混在一起。同步写通常会显著降低IOPS并提高延迟,但它回答的是“应用等待持久化时的响应速度”,而不是“设备在高队列下能完成多少后台写请求”。

如果某个方案在普通随机写中有较高IOPS,但同步写P99很高,则它更适合对持久化确认不敏感的批量任务,不应直接宣传为所有数据库写入场景都更快。

变量四:块大小

块大小改变后,IOPS和吞吐的关系也会改变。4KiB、8KiB、16KiB和1MiB测试的是不同能力:

  • 4KiB或8KiB:更接近部分数据库页、缓存和索引访问;
  • 16KiB或32KiB:可用于观察中等大小业务请求;
  • 1MiB:更接近备份、镜像和大文件连续传输。

块大小测试时,队列深度、读写模式和运行时长必须保持不变。例如基线为4KiB随机读,则只把--bs=4k改为--bs=8k或--bs=16k,不要同时修改iodepth和numjobs。

当块大小从4KiB增加到1MiB时,IOPS可能下降,但吞吐量上升,这是正常现象。不能仅以IOPS下降判断NVMe性能变差,应同时查看BW,并用统一单位换算。

文件系统、内核和时间段的影响

文件系统差异要单独测试

XFS和ext4的文件系统行为可能不同,挂载参数也会影响元数据和同步写入表现。比较文件系统时,应准备两个独立的测试卷,或者使用可恢复的快照,确保业务数据已经完成备份。

不要在包含生产数据的分区上直接执行格式化命令。更换文件系统涉及数据覆盖、挂载点变化和服务启动依赖,适用前提是测试盘为空或已有可验证备份;回滚方式是卸载测试卷、恢复原文件系统或从备份恢复,不应把生产盘作为试验对象。

文件级测试的结果包含文件系统和虚拟文件层开销,更接近应用实际情况;原始设备测试更接近后端块设备上限,但风险更高,也可能脱离实际应用路径。两者不能混用来证明同一个结论。

内核或驱动变化必须重新建基线

如果A状态使用旧内核,B状态同时升级到新内核并更换NVMe方案,即使IOPS发生变化,也无法判断到底是驱动、调度器、内核补丁还是存储介质造成的。

更换内核时至少记录:

uname -r
rpm -q kernel
lsmod | grep nvme

完成内核更新后需要重启才能使用新内核。此时应重新执行完整基线,而不是拿重启前最后一次结果直接作为A状态。Rocky Linux的RHEL兼容性有助于保持工具链和系统管理方式一致,但并不意味着不同内核、不同存储控制器或不同云平台后端会得到相同的IOPS。

测试时间段也应作为独立变量

香港服务器的存储后端可能存在共享资源。白天业务高峰、夜间备份时段和低负载时段可能得到不同结果。时间段测试可以作为独立变量,但不能在同一轮中同时更换线路、实例、内核和盘型。

建议记录:

  • 香港机房或可公开识别的区域信息;
  • 实例规格和磁盘套餐;
  • 测试开始和结束时间;
  • 当时的CPU、内存、磁盘和网络负载;
  • 是否存在备份、同步或发布任务;
  • 测试期间的温度和系统日志异常。

如果不同时间段结果差异很大,应先说明共享资源或后台任务的影响,不能直接把高峰期的低IOPS归因于Rocky Linux 9.5。

香港服务器场景要把线路因素剥离

在服务器本机执行的fio测试,主要衡量服务器本地存储路径,不包含用户到香港机房之间的网络延迟。更换访问地区、网络运营商或线路后,远程页面响应可能改变,但这不等于NVMe IOPS发生变化。

可以把验证拆成两层:

  1. 本机存储层:在香港服务器内部执行相同的fio配置,观察IOPS、BW和延迟。
  2. 应用访问层:通过相同的HTTP接口或业务程序访问测试文件,另外记录客户端到服务器的往返延迟、首字节时间和下载速度。

如果远程访问变慢,而本机fio结果不变,优先检查网络路径、应用进程、连接数和服务器负载。如果本机IOPS下降,同时iostat队列、CPU争用或宿主机等待增加,再考虑存储后端或实例资源问题。

香港服务器场景要把线路因素剥离配图

因此,香港地区是部署和网络体验的条件,不应被直接当成NVMe性能变量。比较不同香港服务器产品时,最好固定机房区域、实例规格和磁盘容量;如果这些条件无法固定,就只能把结果表述为两台完整服务器的综合差异,不能声称差异全部来自NVMe SSD。

结果如何形成可复核的判断

用中位数而不是单次峰值

每个条件建议至少完成1次预热和5次正式运行。记录每次的IOPS、BW、平均延迟、P95、P99、CPU占用和异常说明。

一个用于演示的汇总表如下:

条件IOPS中位数平均完成延迟P99延迟5次结果波动
A:基线存储,4KiB随机读398,000117微秒212微秒约2.4%
B:仅改变存储方案,4KiB随机读476,000132微秒410微秒约3.1%

按IOPS中位数计算,B比A高约19.6%;但P99延迟约增加93.4%。因此更准确的表述应是:“在该4KiB随机读和队列深度条件下,B的吞吐能力更高,但尾延迟也更高。”不能简单写成“B全面提升19.6%”。

如果多次运行的波动已经接近两种方案的差异,例如A和B只相差3%,而单组测试本身波动达到4%至5%,则应增加采样次数、延长观察时间或检查后台负载,不能把小幅差距当作稳定优势。具体的可接受波动阈值取决于业务要求,±3%至±5%只能作为测试阶段的参考范围,不是通用标准。

观察是否出现饱和点

当队列深度逐步增加时,可以绘制“队列深度—IOPS”和“队列深度—P99延迟”两组曲线:

  • IOPS持续上升、P99变化较小:说明还有并发处理空间;
  • IOPS开始趋平、P99快速上升:说明继续增加并发主要是在排队;
  • IOPS和CPU占用同时达到高位:可能是实例计算能力限制;
  • IOPS不高但await和P99明显上升:可能存在后端存储争用或虚拟化抖动;
  • 读性能稳定、写性能在长时间运行后下降:需要检查写放大、缓存耗尽、温度或平台写入策略。

这类曲线比单个“最大IOPS”更能说明服务器适合什么负载。数据库在线事务通常更关注低队列下的P95/P99;批量任务则可以接受较高队列和更高平均吞吐。

按业务类型选择测试组合

应用类型优先测试重点观察
数据库随机读4KiB或8KiB随机读,队列深度1至16低队列IOPS、P95、P99
数据库持久化写4KiB随机写,fsync=1同步写延迟和长尾
缓存或搜索索引混合随机读写读写比例变化后的尾延迟
日志追加顺序写、同步写和持续运行吞吐、落盘延迟、长时间稳定性
备份和镜像1MiB或更大块的顺序读写MB/s或MiB/s、持续吞吐
静态文件服务本机顺序读加远程HTTP访问磁盘吞吐、网络带宽、首字节时间

这张表的作用是避免用单一的4KiB随机读结果代表所有应用。如果产品宣传强调高IOPS,应至少补充低队列、混合读写和同步写场景;如果主要面向备份或文件分发,则应把连续吞吐放在更重要的位置。

比较产品时同步记录资源和成本

如果两种香港服务器的vCPU、内存、磁盘容量或月度费用不同,可以增加以下归一化指标:

  • 单vCPU对应的稳定IOPS;
  • 每GiB存储对应的稳定IOPS;
  • 单位月度成本对应的稳定IOPS;
  • 达到目标P99延迟时的可用IOPS。

单位成本IOPS可以写成:

单位成本IOPS = 在指定延迟上限内的稳定IOPS ÷ 月度总成本

月度总成本应包含实例、系统盘、数据盘、备份和可能的流量费用。由于报价和资源库存会变化,正式评测时应填入同一时间获取的实际报价,并注明计费周期。不能拿不同计费口径下的价格直接做排名。

复测条件与适用边界

当Rocky Linux 9.5更新内核、fio版本、文件系统挂载参数、实例规格或NVMe存储方案后,应重新建立基线。服务器迁移到另一台宿主机、出现明显宿主机争用、温度异常、后台备份介入或磁盘容量接近上限时,也不宜继续沿用旧结果。

最终可引用的性能结论应带上完整条件,例如:

在香港指定服务器、Rocky Linux 9.5、指定内核、指定文件系统、4KiB随机读、直接I/O、单作业队列深度8、运行60秒并完成5次采样的条件下,B状态的IOPS中位数高于A状态,但P99延迟同步增加。

这样的表达能够说明测试范围、比较对象和限制。它不把一次峰值扩展成所有应用场景,也不会把香港网络线路、RHEL兼容环境或NVMe设备名称误认为性能提升的唯一原因。只有在本机基线、变量控制、重复采样和业务负载映射都完成后,才能判断这次IOPS变化是否对实际应用有价值。