4. Fio 工具深度使用:安装、Job 文件编写与核心参数详解

Fio(Flexible I/O Tester)是 Linux 内核文件系统性能测试的行业标准工具,由 Jens Axboe(Linux 内核块层维护者)开发。它支持同步/异步 I/O、多种引擎(libaio、io_uring、sync)、自定义负载模型,并能精确控制队列深度、并发数、块大小等关键参数。本章将围绕 Fio 的安装、Job 文件编写以及 rw、bs、iodepth、numjobs 四个核心参数展开深度讲解。

学习目标:掌握 Fio 的二进制安装与源码编译;理解 Job 文件的语法结构;能够独立编写针对顺序读、随机写、混合负载的测试 Job;深入理解 iodepth 与 numjobs 对 IOPS 和延迟的影响机制。

4.1 Fio 安装:二进制包与源码编译

Fio 的安装方式分为两种:通过系统包管理器安装(快速,版本可能较旧)和从源码编译安装(获取最新特性,如 io_uring 引擎支持)。

4.1.1 二进制包安装(推荐用于快速验证)

发行版 安装命令 默认版本(示例)
Ubuntu / Debian sudo apt-get install fio -y 3.28+
RHEL / CentOS 7 sudo yum install fio -y 3.19
RHEL / CentOS 8 / Rocky sudo dnf install fio -y 3.26+
openSUSE sudo zypper install fio 3.30+

4.1.2 源码编译安装(获取最新 io_uring 支持)

对于需要测试 Linux 5.1+ 内核原生异步 I/O 引擎 io_uring 的场景,建议从 GitHub 源码编译:

# 安装依赖(Ubuntu/Debian)
sudo apt-get install build-essential libaio-dev libnuma-dev -y

# 克隆最新源码
git clone https://github.com/axboe/fio.git
cd fio

# 配置、编译、安装
./configure
make -j$(nproc)
sudo make install

# 验证安装
fio --version
fio --engines | grep io_uring   # 确认 io_uring 引擎可用
关键检查点:执行 fio --engines 查看支持的 I/O 引擎列表。如果缺少 io_uring,说明内核版本或 liburing 库未正确安装。对于生产环境性能测试,优先使用 io_uring 或 libaio 引擎。

4.2 Job 文件编写:结构化测试描述

Fio 支持命令行参数和 Job 文件两种方式。Job 文件是推荐的生产级做法,它将测试配置、目标设备、负载模型和输出格式封装在一个可复用的文本文件中。Job 文件使用 key=value 语法,支持全局段 [global] 和多个 Job 段。

4.2.1 Job 文件基本结构

; 注释行以分号或 # 开头
[global]
ioengine=libaio
direct=1
runtime=60
time_based
group_reporting

[randwrite-4k]
rw=randwrite
bs=4k
size=1G
iodepth=32
numjobs=4

[read-128k]
rw=read
bs=128k
size=2G
iodepth=8
numjobs=2

上述文件定义了两个 Job:randwrite-4k 模拟 4KB 随机写(高 IOPS 场景),read-128k 模拟 128KB 顺序读(高吞吐场景)。[global] 段中的参数对所有 Job 生效,除非被 Job 段覆盖。

4.2.2 常用 Job 文件参数速查表

参数 说明 典型值
filename 测试目标文件或块设备 /dev/nvme0n1 或 /mnt/test/fio.dat
size 每个 Job 处理的 I/O 总大小 1G, 10G, 100%
runtime 测试持续时间(秒) 60, 300
time_based 即使 size 未完成,也运行满 runtime 无值(标志位)
direct 绕过页缓存,直接 I/O 1(启用)
group_reporting 合并多个 Job 的统计报告 无值(标志位)
ioengine 异步 I/O 引擎 libaio, io_uring, sync
注意:当测试目标为块设备(如 /dev/sdb)时,必须设置 direct=1 且 filename 指向设备文件。测试前请确认设备上无重要数据,Fio 会直接读写设备,可能导致数据损坏。

4.3 核心参数详解:rw、bs、iodepth、numjobs

这四个参数构成了 Fio 负载模型的核心四元组,它们共同决定了测试的 I/O 模式、数据包大小、并发深度和并行度。

4.3.1 rw:I/O 读写模式

rw 参数定义测试的访问模式,是负载模型的“形状”。

rw 值 含义 典型场景
read 顺序读 大文件流式读取,如视频点播
write 顺序写 日志写入、数据备份
randread 随机读 数据库查询、搜索引擎
randwrite 随机写 OLTP 事务日志、缓存更新
rw 顺序混合读写(默认 50% 读 / 50% 写) 文件服务器混合负载
randrw 随机混合读写 数据库在线事务处理(OLTP)

混合模式下可通过 rwmixread=70 调整读占比(70% 读,30% 写)。

4.3.2 bs:块大小

bs 定义每次 I/O 操作的数据块大小,直接影响测试的 IOPS 与带宽表现。块越小,IOPS 越高;块越大,带宽越高。

bs 值 典型 IOPS(NVMe SSD 参考) 典型带宽 适用场景
4K 800K ~ 1.5M ~ 6 GB/s 数据库随机读写、元数据操作
64K 100K ~ 200K ~ 8 GB/s 虚拟化存储、中等粒度传输
1M 8K ~ 15K ~ 12 GB/s 大文件顺序读写、视频流

Fio 支持多块大小混合,例如 bs=4k,64k,1M 表示按比例随机选择块大小。

4.3.3 iodepth:I/O 队列深度

iodepth 是异步 I/O 引擎(libaio/io_uring)的核心参数,表示操作系统或存储设备可以同时排队的 I/O 请求数量。它直接决定了设备的并发利用率和延迟表现。

  • iodepth=1:串行 I/O,每次只发一个请求,等待完成后再发下一个。延迟最低,但 IOPS 受限。
  • iodepth=32:典型值,NVMe SSD 在此深度下达到饱和 IOPS。
  • iodepth=128:高队列深度,用于测试设备极限吞吐,但可能增加延迟。
经验法则:对于 NVMe SSD,建议从 iodepth=1 开始逐步增加,观察 IOPS 和延迟的拐点。当 IOPS 不再随 iodepth 线性增长时,说明设备或驱动已达到饱和。

4.3.4 numjobs:并发进程/线程数

numjobs 控制 Fio 启动的并发进程(或线程,取决于 thread 参数)数量。每个 Job 实例拥有独立的 I/O 上下文和队列深度。

  • numjobs=1:单进程测试,适合评估单线程性能。
  • numjobs=4:4 个进程并发,模拟多应用或 CPU 多核并行 I/O。
  • numjobs=16:高并发测试,用于验证存储系统在多租户场景下的表现。

iodepth 与 numjobs 的乘积 决定了系统总的 I/O 并发度(总队列深度 = iodepth × numjobs)。例如 iodepth=32, numjobs=4 意味着系统同时处理 128 个 I/O 请求。

4.4 核心参数交互关系:SVG 架构图

下图展示了 rw、bs、iodepth、numjobs 四个参数如何协同定义 Fio 负载模型,并最终影响 IOPS、带宽和延迟三个核心指标。

Fio 核心参数交互与性能影响模型 rw (读写模式) 顺序/随机/混合 bs (块大小) 4K / 64K / 1M iodepth (队列深度) 1 ~ 128 numjobs (并发数) 1 ~ 16+ Fio 负载模型 总并发度 = iodepth × numjobs IOPS 每秒 I/O 操作数 带宽 (BW) MB/s 或 GB/s 延迟 (Lat) usec / msec 参数调优原则 小 bs (4K) + 高 iodepth → 测试 IOPS 极限 大 bs (1M) + 低 iodepth → 测试带宽极限

4.5 实战案例:编写完整的 Fio Job 文件

以下是一个针对 NVMe SSD 的完整性能评估 Job 文件,覆盖随机 4K 写、顺序 128K 读和混合随机负载三种场景。

; nvme_benchmark.fio
; 目标设备:/dev/nvme0n1(请根据实际设备修改)
[global]
ioengine=io_uring
direct=1
runtime=120
time_based
group_reporting
filename=/dev/nvme0n1
; 注意:使用块设备时,size 参数会被忽略,Fio 使用整个设备

[randwrite-4k-qd32]
rw=randwrite
bs=4k
iodepth=32
numjobs=4
; 预期:高 IOPS,关注 99.99% 延迟

[seqread-128k-qd8]
rw=read
bs=128k
iodepth=8
numjobs=2
; 预期:高带宽,关注吞吐量

[randrw-4k-qd16]
rw=randrw
rwmixread=70
bs=4k
iodepth=16
numjobs=4
; 预期:混合负载,70% 读 + 30% 写

执行命令:

fio nvme_benchmark.fio
输出解读:Fio 报告会为每个 Job 输出 IOPS、带宽(BW)、延迟(lat)的均值、最大值和百分位值。重点关注 slat(提交延迟)、clat(完成延迟)和 lat(总延迟)的 p99 和 p99.99 值,它们反映了存储系统的尾部延迟表现。

4.6 常见陷阱与最佳实践

陷阱 说明 解决方案
未设置 direct=1 测试结果受页缓存影响,不反映真实设备性能 始终设置 direct=1,除非测试文件系统缓存路径
iodepth 与 numjobs 乘积过大 总队列深度超过设备或驱动能力,导致延迟飙升 从 iodepth=1, numjobs=1 开始逐步增加,观察拐点
测试时间过短 设备未进入稳态,结果偏高 设置 runtime=300(5 分钟)以上,观察稳态性能
忽略 group_reporting 多 Job 时输出分散,难以汇总 在 [global] 段添加 group_reporting