4. Fio 工具深度使用:安装、Job 文件编写与核心参数详解
Fio(Flexible I/O Tester)是 Linux 内核文件系统性能测试的行业标准工具,由 Jens Axboe(Linux 内核块层维护者)开发。它支持同步/异步 I/O、多种引擎(libaio、io_uring、sync)、自定义负载模型,并能精确控制队列深度、并发数、块大小等关键参数。本章将围绕 Fio 的安装、Job 文件编写以及 rw、bs、iodepth、numjobs 四个核心参数展开深度讲解。
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:高队列深度,用于测试设备极限吞吐,但可能增加延迟。
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、带宽和延迟三个核心指标。
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
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 |