Fio

Fio

fio 是一个通用 I/O 压测工具,全名 Flexible I/O Tester。它常用来测试 SSD、NVMe、文件系统、块设备的吞吐、IOPS、延迟、队列深度行为等。对你写 SSD 固件来说,fio 很适合验证 FTL、GC、wearleveling、write cliff、读写延迟抖动这些问题。

安装

sudo apt-get install fio
fio --version

概念

Job

fio的测试任务被组织为一个或多个"作业"(Job)。每个作业定义了一组特定的I/O参数和行为。一个作业文件中可以包含多个作业定义。

I/O引擎(I/O Engine)

fio支持多种I/O引擎,用于实现不同的I/O操作方式。常见的I/O引擎包括:

libaio:Linux异步I/O
sync:同步I/O
mmap:内存映射I/O
psync:POSIX同步I/O
io_uring:Linux新的异步I/O接口(需要内核4.18+)

块大小(Block Size)

指每次I/O操作的数据大小,通常以bs参数指定,可以是字节(B)、千字节(K)、兆字节(M)等单位。

I/O模式(I/O Pattern)

fio支持多种I/O模式,主要包括:

  • read:顺序读
  • write:顺序写
  • randread:随机读
  • randwrite:随机写
  • randrw:混合随机读写

队列深度(I/O Depth)

指在等待前一批I/O完成之前,可以提交的最大I/O请求数。对于异步I/O引擎(如libaio),队列深度是一个重要的性能调优参数。

核心概念

直接I/O(Direct I/O)

通过设置direct=1参数,fio可以绕过操作系统的文件缓存,直接与存储设备进行I/O操作,这对于评估底层存储设备的真实性能非常有用

命令参数

fio 的测试由几个参数决定:

参数 含义 具体样例
--name 测试任务名称,便于识别结果 --name=seq-read
--filename 测试目标,可以是普通文件或块设备 --filename=/mnt/testfile 或 --filename=/dev/nvme0n1
--rw 访问模式:read 顺序读、write 顺序写、randread 随机读、randwrite 随机写、randrw 随机混合读写 --rw=randread
如果是--rw=randrw
需要指定比例--rwmixread=70
--bs 每次 I/O 的块大小 --bs=4k、--bs=128k
--iodepth I/O 队列深度;常用值有 1、4、32、64 --iodepth=32
--numjobs 并发 job 数量 --numjobs=4
--size 每个 job 使用的测试数据范围 --size=10G
--runtime 测试运行时长,通常以秒为单位 --runtime=60
--time_based 启用按时间运行;达到 runtime 后结束,而不是写满 size 后结束 --time_based
--direct 是否使用直接 I/O;1 通常用于绕过页缓存,测试更贴近设备 I/O --direct=1
--ioengine I/O 引擎:
libaio:Linux异步I/O
sync:同步I/O
mmap:内存映射I/O
psync:POSIX同步I/O
io_uring:Linux新的异步I/O接口(需要内核4.18+)
Linux 上常用 libaio 或 io_uring;
--ioengine=libaio
--group_reporting 多个 job 时汇总显示结果 --group_reporting
--rate I/O速率限制 --rate=100M
--stonewall 等待前一个作业完成后再开始 stonewall
--rwmixread 设置混合读写时的读操作比例,取值通常为 0–100;例如设为 70 表示约 70% 读、30% 写。用于 --rw=randrw 或 --rw=rw 等混合模式 --rw=randrw --rwmixread=70
--rw_sequencer 控制随机 I/O 序列的生成方式,例如按偏移递增或按随机顺序访问。具体可选值取决于 fio 版本,使用前可查看 fio --cmdhelp=rw_sequencer --rw_sequencer=sequential
--randrepeat 控制随机 I/O 序列是否可重复:1 表示使用可重复的随机序列,0 表示每次生成不同序列 --randrepeat=0
--norandommap 禁用随机偏移映射,允许随机 I/O 重复访问相同区域;启用后可能出现重复访问 --norandommap

样例:

fio --name=test \
      --filename=/mnt/ssd/fio.test \
      --rw=randread \
      --bs=4k \
      --iodepth=32 \
      --numjobs=1 \
      --size=4G \
      --runtime=60 \
      --time_based \
      --direct=1 \
      --ioengine=libaio \
      --group_reporting

fio可以记录实际应用的I/O模式,并在测试中重放:

记录I/O轨迹:
fio --name=trace --filename=/dev/sdb --rw=trace --trace=/tmp/io-trace
bash
重放I/O轨迹:
fio --name=replay --filename=/dev/sdc --rw=replay --replay=/tmp/io-trace

生成图表和报告
虽然fio本身不直接生成图表,但可以将结果输出为JSON格式,然后使用其他工具生成图表:

fio --name=test --rw=randread --bs=4K --size=10G --output-format=json --output=results.json

fio文件

  mkdir -p ~/fio-lab
  cd ~/fio-lab

nvim learn.fio

# 全局配置:下面的参数会作为默认值应用到后续所有 job。
[global]
# 测试文件路径。当前会在运行 fio 的目录下创建/使用 fio.test。
filename=fio.test
# 测试文件大小。512m 适合快速学习;正式压测建议改大,例如 10g 或更大。
size=512m
# 使用 direct I/O,尽量绕过操作系统页缓存,让结果更接近磁盘本身。
direct=1
# 使用 Linux 异步 I/O 引擎。iodepth > 1 时通常需要异步引擎才能发挥作用。
ioengine=libaio
# 同一个 job 里有多个线程/进程时合并汇总输出;这里保留为通用配置。
group_reporting=1
# 每个 time_based=1 的测试 job 持续运行 20 秒。
runtime=20
# 按时间运行,而不是只完成固定 size 的 I/O 后就退出。
time_based=1
# 预热 3 秒,预热阶段的数据不计入最终统计。
ramp_time=3

# 准备阶段:先顺序写满测试文件,避免后续读测试读到稀疏文件或未初始化区域。
[prepare]
rw=write
bs=1m
iodepth=1
# prepare 只写满 size 指定的 512m 文件,不按 runtime 重复运行。
time_based=0


# 128K 顺序读:观察大块连续读取吞吐能力。
[seq-read-128k]
# 等上一个 job 完成后再运行当前 job,避免不同测试互相干扰。
stonewall
rw=read
bs=128k
iodepth=16

# 4K 随机读:观察小块随机读取 IOPS 和延迟。
[rand-read-4k]
stonewall
rw=randread
bs=4k
iodepth=16

# 4K 随机写:观察小块随机写入 IOPS、带宽和尾延迟。
[rand-write-4k]
stonewall
rw=randwrite
bs=4k
iodepth=16

# 4K 随机混合读写:模拟 70% 读、30% 写的混合负载。
[randrw-70read-30write]
stonewall
rw=randrw
# randrw 模式下读请求占 70%,写请求占 30%。
rwmixread=70
bs=4k
iodepth=16

运行:

fio learn.fio

运行结果分析

运行结果:

prepare: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=1
seq-read-128k: (g=1): rw=read, bs=(R) 128KiB-128KiB, (W) 128KiB-128KiB, (T) 128KiB-128KiB, ioengine=libaio, iodepth=16
rand-read-4k: (g=2): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=16
rand-write-4k: (g=3): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=16
randrw-70read-30write: (g=4): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=16
fio-3.36
Starting 5 processes
prepare: Laying out IO file (1 file / 512MiB)
Jobs: 1 (f=1): [_(4),m(1)][100.0%][r=232MiB/s,w=100MiB/s][r=59.5k,w=25.6k IOPS][eta 00m:00s]
prepare: (groupid=0, jobs=1): err= 0: pid=6496: Fri Jun 12 00:19:44 2026
  write: IOPS=2370, BW=2370MiB/s (2486MB/s)(512MiB/216msec); 0 zone resets
  cpu          : usr=13.02%, sys=0.00%, ctx=513, majf=0, minf=10
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,512,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1
seq-read-128k: (groupid=1, jobs=1): err= 0: pid=6497: Fri Jun 12 00:19:44 2026
  read: IOPS=44.9k, BW=5615MiB/s (5887MB/s)(110GiB/20001msec)
    slat (usec): min=2, max=1078, avg= 4.97, stdev= 6.72
    clat (usec): min=107, max=4305, avg=350.89, stdev=67.80
     lat (usec): min=147, max=4308, avg=355.85, stdev=67.01
    clat percentiles (usec):
     |  1.00th=[  235],  5.00th=[  281], 10.00th=[  302], 20.00th=[  318],
     | 30.00th=[  326], 40.00th=[  334], 50.00th=[  343], 60.00th=[  351],
     | 70.00th=[  359], 80.00th=[  375], 90.00th=[  408], 95.00th=[  457],
     | 99.00th=[  578], 99.50th=[  619], 99.90th=[  783], 99.95th=[  971],
     | 99.99th=[ 2540]
   bw (  MiB/s): min= 5503, max= 5747, per=100.00%, avg=5619.13, stdev=60.24, samples=37
   iops        : min=44024, max=45981, avg=44952.54, stdev=481.88, samples=37
  lat (usec)   : 250=1.85%, 500=95.10%, 750=2.93%, 1000=0.07%
  lat (msec)   : 2=0.03%, 4=0.01%, 10=0.01%
  cpu          : usr=3.87%, sys=26.30%, ctx=446742, majf=0, minf=38
  IO depths    : 1=0.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=100.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=898370,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16
rand-read-4k: (groupid=2, jobs=1): err= 0: pid=6498: Fri Jun 12 00:19:44 2026
  read: IOPS=93.9k, BW=367MiB/s (385MB/s)(7337MiB/20001msec)
    slat (nsec): min=772, max=234899, avg=1224.20, stdev=1178.79
    clat (usec): min=22, max=5188, avg=168.87, stdev=37.20
     lat (usec): min=54, max=5189, avg=170.10, stdev=37.16
    clat percentiles (usec):
     |  1.00th=[  114],  5.00th=[  129], 10.00th=[  137], 20.00th=[  145],
     | 30.00th=[  151], 40.00th=[  157], 50.00th=[  165], 60.00th=[  174],
     | 70.00th=[  182], 80.00th=[  190], 90.00th=[  206], 95.00th=[  221],
     | 99.00th=[  265], 99.50th=[  293], 99.90th=[  359], 99.95th=[  396],
     | 99.99th=[ 1205]
   bw (  KiB/s): min=345338, max=383534, per=100.00%, avg=376024.73, stdev=7578.18, samples=37
   iops        : min=86334, max=95883, avg=94005.92, stdev=1894.50, samples=37
  lat (usec)   : 50=0.01%, 100=0.21%, 250=98.23%, 500=1.53%, 750=0.01%
  lat (usec)   : 1000=0.01%
  lat (msec)   : 2=0.02%, 4=0.01%, 10=0.01%
  cpu          : usr=5.22%, sys=16.59%, ctx=571835, majf=0, minf=37
  IO depths    : 1=0.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=100.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=1878268,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16
rand-write-4k: (groupid=3, jobs=1): err= 0: pid=6499: Fri Jun 12 00:19:44 2026
  write: IOPS=74.7k, BW=292MiB/s (306MB/s)(5836MiB/20001msec); 0 zone resets
    slat (nsec): min=841, max=300493, avg=1472.69, stdev=1209.35
    clat (usec): min=26, max=31651, avg=212.45, stdev=201.37
     lat (usec): min=28, max=31653, avg=213.92, stdev=201.36
    clat percentiles (usec):
     |  1.00th=[  137],  5.00th=[  163], 10.00th=[  169], 20.00th=[  180],
     | 30.00th=[  186], 40.00th=[  192], 50.00th=[  196], 60.00th=[  202],
     | 70.00th=[  208], 80.00th=[  217], 90.00th=[  229], 95.00th=[  245],
     | 99.00th=[  791], 99.50th=[ 1188], 99.90th=[ 1991], 99.95th=[ 2212],
     | 99.99th=[ 7439]
   bw (  KiB/s): min=152798, max=346035, per=100.00%, avg=301335.95, stdev=43057.67, samples=37
   iops        : min=38199, max=86508, avg=75333.65, stdev=10764.46, samples=37
  lat (usec)   : 50=0.01%, 100=0.25%, 250=95.59%, 500=2.76%, 750=0.34%
  lat (usec)   : 1000=0.35%
  lat (msec)   : 2=0.61%, 4=0.07%, 10=0.02%, 20=0.01%, 50=0.01%
  cpu          : usr=5.30%, sys=12.93%, ctx=533946, majf=0, minf=42
  IO depths    : 1=0.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=100.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,1494034,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16
randrw-70read-30write: (groupid=4, jobs=1): err= 0: pid=6500: Fri Jun 12 00:19:44 2026
  read: IOPS=44.2k, BW=173MiB/s (181MB/s)(3457MiB/20001msec)
    slat (nsec): min=830, max=750803, avg=1695.74, stdev=2624.31
    clat (usec): min=17, max=38076, avg=300.03, stdev=395.25
     lat (usec): min=67, max=38077, avg=301.73, stdev=395.52
    clat percentiles (usec):
     |  1.00th=[   97],  5.00th=[  121], 10.00th=[  145], 20.00th=[  167],
     | 30.00th=[  180], 40.00th=[  188], 50.00th=[  196], 60.00th=[  206],
     | 70.00th=[  219], 80.00th=[  241], 90.00th=[  429], 95.00th=[ 1221],
     | 99.00th=[ 1909], 99.50th=[ 2057], 99.90th=[ 2409], 99.95th=[ 2704],
     | 99.99th=[ 4146]
   bw (  KiB/s): min=88342, max=244077, per=100.00%, avg=177531.41, stdev=67074.31, samples=39
   iops        : min=22085, max=61019, avg=44382.54, stdev=16768.61, samples=39
  write: IOPS=18.9k, BW=74.0MiB/s (77.6MB/s)(1481MiB/20001msec); 0 zone resets
    slat (nsec): min=923, max=274820, avg=1980.34, stdev=2663.87
    clat (usec): min=6, max=4215, avg=136.68, stdev=48.25
     lat (usec): min=27, max=4216, avg=138.66, stdev=47.74
    clat percentiles (usec):
     |  1.00th=[   49],  5.00th=[   60], 10.00th=[   70], 20.00th=[   93],
     | 30.00th=[  120], 40.00th=[  137], 50.00th=[  147], 60.00th=[  153],
     | 70.00th=[  161], 80.00th=[  172], 90.00th=[  182], 95.00th=[  192],
     | 99.00th=[  237], 99.50th=[  277], 99.90th=[  375], 99.95th=[  433],
     | 99.99th=[  635]
   bw (  KiB/s): min=37922, max=104878, per=100.00%, avg=76029.31, stdev=28722.69, samples=39
   iops        : min= 9480, max=26219, avg=19006.95, stdev=7180.73, samples=39
  lat (usec)   : 10=0.01%, 20=0.01%, 50=0.38%, 100=7.40%, 250=79.08%
  lat (usec)   : 500=6.63%, 750=1.17%, 1000=0.99%
  lat (msec)   : 2=3.90%, 4=0.44%, 10=0.01%, 20=0.01%, 50=0.01%
  cpu          : usr=5.25%, sys=13.82%, ctx=403341, majf=0, minf=38
  IO depths    : 1=0.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=100.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=884942,379015,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16

Run status group 0 (all jobs):
  WRITE: bw=2370MiB/s (2486MB/s), 2370MiB/s-2370MiB/s (2486MB/s-2486MB/s), io=512MiB (537MB), run=216-216msec

Run status group 1 (all jobs):
   READ: bw=5615MiB/s (5887MB/s), 5615MiB/s-5615MiB/s (5887MB/s-5887MB/s), io=110GiB (118GB), run=20001-20001msec

Run status group 2 (all jobs):
   READ: bw=367MiB/s (385MB/s), 367MiB/s-367MiB/s (385MB/s-385MB/s), io=7337MiB (7693MB), run=20001-20001msec

Run status group 3 (all jobs):
  WRITE: bw=292MiB/s (306MB/s), 292MiB/s-292MiB/s (306MB/s-306MB/s), io=5836MiB (6120MB), run=20001-20001msec

Run status group 4 (all jobs):
   READ: bw=173MiB/s (181MB/s), 173MiB/s-173MiB/s (181MB/s-181MB/s), io=3457MiB (3625MB), run=20001-20001msec
  WRITE: bw=74.0MiB/s (77.6MB/s), 74.0MiB/s-74.0MiB/s (77.6MB/s-77.6MB/s), io=1481MiB (1552MB), run=20001-20001msec

Disk stats (read/write):
  sdd: ios=4136765/2154907, sectors=288619952/18285136, merge=0/71, ticks=1000530/385245, in_queue=1385779, util=97.89%

片段分析:

seq-read-test: (g=0): rw=read, bs=(R) 256KiB-256KiB, (W) 256KiB-256KiB, (T) 256KiB-256KiB, ioengine=libaio, iodepth=16
fio-3.33
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=556MiB/s][r=2281 IOPS][eta 00m:00s]
seq-read-test: (groupid=0, jobs=1): err= 0: pid=12345: Wed Jun 12 10:00:00 2024
  read: IOPS=2256, BW=564MiB/s (591MB/s)(33.8GiB/61001msec)
    slat (usec): min=4, max=287, avg= 8.23, stdev= 5.12
    clat (usec): min=12, max=2403, avg=6982.34, stdev=123.45
     lat (usec): min=16, max=2407, avg=6990.57, stdev=123.47
    clat percentiles (usec):
     |  1.00th=[ 6500],  5.00th=[ 6700], 10.00th=[ 6800], 20.00th=[ 6900],
     | 30.00th=[ 6900], 40.00th=[ 7000], 50.00th=[ 7000], 60.00th=[ 7000],
     | 70.00th=[ 7100], 80.00th=[ 7100], 90.00th=[ 7200], 95.00th=[ 7300],
     | 99.00th=[ 7500], 99.50th=[ 7600], 99.90th=[ 7800], 99.95th=[ 8000],
     | 99.99th=[23000]
  bw (  KiB/s): min=540000, max=580000, per=100.00%, avg=577892.34, stdev=12345.67, samples=122
  iops        : min= 2109, max= 2265, avg=2256.23, stdev=48.12, samples=122
  lat (usec)   : 20=0.01%, 50=0.1%, 100=0.5%, 250=1.0%, 500=2.0%
  lat (msec)   : 2=5.0%, 4=10.0%, 10=80.0%, 20=1.4%, 50=0.01%
  cpu          : usr=2.00%, sys=8.00%, ctx=138000, majf=0, minf=123
  IO depths    : 1=0.1%, 2=0.2%, 4=0.4%, 8=0.8%, 16=98.5%, 32=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=87808,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16
 
Run status group 0 (all jobs):
   READ: bw=564MiB/s (591MB/s), 564MiB/s-564MiB/s (591MB/s-591MB/s), io=33.8GiB (36.3GB), run=61001-61001msec
  • 延迟指标:
    • slat: 提交延迟,平均8.23微秒。
    • clat: 完成延迟,平均6982.34微秒(约7毫秒)。
    • lat: 总延迟,平均6990.57微秒。
    • 延迟百分位数: 例如,99.9%的I/O操作延迟小于7800微秒(7.8毫秒)。
  • BW: 564MiB/s。这是测试中达到的吞吐量。
  • IOPS: 2256次/秒。这表示存储系统每秒可以处理约2256次I/O操作。
  • CPU使用率: 用户空间2%,系统空间8%,总CPU使用率约10%。
  • I/O队列深度: 主要集中在16,与测试中设置的iodepth=16相符。

常见性能问题判断

高CPU使用率+低IOPS: 可能是CPU成为瓶颈,或I/O模式效率低下。

低CPU使用率+低IOPS: 可能是存储设备本身性能不足。

高延迟+低IOPS: 可能是存储系统存在内部瓶颈,如缓存命中率低或RAID控制器性能不足。

波动大的性能指标: 可能是系统配置不当或存在资源竞争。

posted @ 2026-11-08 21:53  aswd  阅读(3)  评论(0)    收藏  举报