Linux fio命令

fio命令 - Flexible I/O Tester,一款功能强大的磁盘I/O性能测试工具,支持多种I/O引擎和测试模式。
警告:fio是磁盘性能测试工具,运行时会进行大量磁盘读写操作,可能对现有数据造成破坏,请务必在测试环境中使用!

命令简介

fio(Flexible I/O Tester)是一个用于基准测试和压力测试磁盘和文件系统的工具。它支持多种I/O引擎(同步/异步、直接I/O、内存映射等)、多种I/O类型(顺序/随机读写)和详细的统计报告。广泛用于评估存储设备的性能、验证硬件规格和系统调优。

安装方法

# Ubuntu/Debian
sudo apt-get install fio

# RHEL/CentOS 7
sudo yum install fio

# RHEL/CentOS 8/Fedora
sudo dnf install fio

# Arch Linux
sudo pacman -S fio

# 从源码编译安装
git clone https://github.com/axboe/fio
cd fio
./configure
make
sudo make install

# 验证安装
fio --version

基本语法

# 命令行直接测试
fio [选项] [任务文件]

# 使用任务文件(推荐)
fio jobfile.fio

核心概念

I/O引擎
  • libaio: Linux原生异步I/O
  • sync: 基本同步I/O
  • psync: 预读同步I/O
  • posixaio: POSIX异步I/O
  • mmap: 内存映射文件
  • splice: Linux splice I/O
  • null: 空操作(仅用于测试框架)
I/O类型
  • read: 顺序读
  • write: 顺序写
  • randread: 随机读
  • randwrite: 随机写
  • rw: 混合读写
  • randrw: 随机混合读写
  • trim: TRIM/丢弃操作

常用参数

参数 说明 示例
--name= 测试任务名称 --name=test_job
--filename= 测试文件路径 --filename=/dev/sdb--filename=testfile
--size= 测试文件大小 --size=1G, --size=100%(使用全部空间)
--rw= I/O操作类型 --rw=read, --rw=randwrite, --rw=randrw
--bs= 块大小(block size) --bs=4k, --bs=1M, --bs=4k,8k(混合)
--ioengine= I/O引擎类型 --ioengine=libaio, --ioengine=sync
--iodepth= I/O队列深度 --iodepth=32(常用于异步I/O)
--numjobs= 并发任务数 --numjobs=4(模拟4个并发客户端)
--runtime= 运行时间(秒) --runtime=60(运行60秒)
--time_based 基于时间而非大小运行 --time_based
--direct= 是否使用直接I/O(绕过缓存) --direct=1(启用)
--group_reporting 分组报告统计信息 --group_reporting
--output= 输出结果文件 --output=result.json
--output-format= 输出格式 --output-format=json,normal

使用示例

示例1:基本磁盘性能测试

# 测试顺序读性能(1M块大小,运行60秒)
fio --name=seq_read --filename=/dev/sdb --rw=read --bs=1M \
    --size=10G --runtime=60 --ioengine=libaio --direct=1 \
    --group_reporting

# 测试顺序写性能
fio --name=seq_write --filename=/dev/sdb --rw=write --bs=1M \
    --size=10G --runtime=60 --ioengine=libaio --direct=1 \
    --group_reporting

示例2:4K随机读写测试(常用)

# 4K随机读测试
fio --name=4k_randread --filename=/dev/sdb --rw=randread --bs=4k \
    --size=10G --runtime=60 --ioengine=libaio --iodepth=32 \
    --direct=1 --group_reporting

# 4K随机写测试
fio --name=4k_randwrite --filename=/dev/sdb --rw=randwrite --bs=4k \
    --size=10G --runtime=60 --ioengine=libaio --iodepth=32 \
    --direct=1 --group_reporting

示例3:混合读写测试

# 70%读,30%写的混合测试
fio --name=mixed_rw --filename=/dev/sdb --rw=randrw --rwmixread=70 \
    --rwmixwrite=30 --bs=4k --size=10G --runtime=60 \
    --ioengine=libaio --iodepth=32 --direct=1 --group_reporting

示例4:使用任务文件

创建测试配置文件 test.fio

# test.fio - 顺序读写测试
[global]
ioengine=libaio
iodepth=16
size=1G
direct=1
runtime=30
time_based

[seq-read]
name=sequential-read-test
filename=/dev/sdb
rw=read
bs=1M

[seq-write]
name=sequential-write-test
filename=/dev/sdb
rw=write
bs=1M

[rand-read]
name=random-read-test
filename=/dev/sdb
rw=randread
bs=4k

[rand-write]
name=random-write-test
filename=/dev/sdb
rw=randwrite
bs=4k

运行任务文件:

fio test.fio

示例5:并发测试

# 4个并发任务进行随机读测试
fio --name=concurrent_test --filename=/dev/sdb --rw=randread \
    --bs=4k --size=10G --runtime=60 --ioengine=libaio \
    --iodepth=32 --numjobs=4 --direct=1 --group_reporting

# 每个任务使用不同的文件
fio --name=multi_file --filename=/dev/sdb:/dev/sdc:/dev/sdd \
    --rw=randread --bs=4k --size=10G --runtime=60 \
    --ioengine=libaio --iodepth=32 --numjobs=3 --direct=1

示例6:数据库工作负载模拟

# 模拟OLTP数据库负载(8K随机读写,75%读,25%写)
fio --name=oltp_sim --filename=/dev/sdb --rw=randrw \
    --rwmixread=75 --rwmixwrite=25 --bs=8k --size=20G \
    --runtime=120 --ioengine=libaio --iodepth=128 \
    --numjobs=8 --direct=1 --group_reporting

示例7:输出JSON格式结果

# 生成JSON格式的测试报告
fio --name=test --filename=/dev/sdb --rw=randread --bs=4k \
    --size=1G --runtime=30 --ioengine=libaio --direct=1 \
    --output=result.json --output-format=json

# 同时生成普通和JSON格式
fio --name=test --filename=/dev/sdb --rw=randread --bs=4k \
    --size=1G --runtime=30 --ioengine=libaio --direct=1 \
    --output=result.txt --output-format=json,normal

示例8:网络存储测试

# 测试NFS共享
fio --name=nfs_test --filename=/mnt/nfs/testfile --rw=randread \
    --bs=4k --size=10G --runtime=60 --ioengine=libaio \
    --iodepth=16 --direct=1 --group_reporting

# 测试iSCSI LUN
fio --name=iscsi_test --filename=/dev/sdc --rw=randrw \
    --bs=8k --size=50G --runtime=120 --ioengine=libaio \
    --iodepth=32 --numjobs=4 --direct=1

结果解读

关键性能指标
指标 说明 单位 参考值
BW (Bandwidth) 带宽,单位时间内的数据传输量 KB/s, MB/s 越高越好
IOPS 每秒I/O操作数 ops/s 越高越好(特别是4K随机)
lat (Latency) 延迟,I/O操作的响应时间 μs, ms 越低越好
clat 完成延迟(completion latency) μs, ms 越低越好
slat 提交延迟(submission latency) μs, ms 越低越好
bw_mean 平均带宽 KB/s, MB/s 稳定值
iops_mean 平均IOPS ops/s 稳定值

典型测试场景

场景 块大小 I/O类型 队列深度 目的
HDD性能基准 1M 顺序读/写 1-4 测试最大连续传输速度
SSD性能基准 4K, 8K 随机读/写 32-256 测试随机访问性能
数据库OLTP 8K 随机混合读写 64-256 模拟数据库负载
虚拟机存储 4K, 8K, 64K 混合随机读写 32-128 测试虚拟化环境性能
视频流媒体 64K-1M 顺序读 4-16 测试大文件连续读取
备份服务器 256K-1M 顺序写 4-16 测试大文件写入性能

自动化测试脚本

自动化性能测试脚本
#!/bin/bash
# 自动化fio性能测试脚本
DEVICE="/dev/sdb"
OUTPUT_DIR="/var/log/fio_tests"
LOG_FILE="$OUTPUT_DIR/fio_results_$(date +%Y%m%d_%H%M%S).log"
TEST_DURATION=60

mkdir -p $OUTPUT_DIR

echo "=== fio性能测试报告 $(date) ===" > $LOG_FILE
echo "测试设备: $DEVICE" >> $LOG_FILE
echo "测试时长: ${TEST_DURATION}秒" >> $LOG_FILE
echo "" >> $LOG_FILE

# 测试函数
run_test() {
    local test_name=$1
    local rw_type=$2
    local block_size=$3
    local iodepth=$4

    echo "运行测试: $test_name (${rw_type}, ${block_size}, iodepth=${iodepth})" | tee -a $LOG_FILE

    fio --name="$test_name" --filename="$DEVICE" --rw="$rw_type" \
        --bs="$block_size" --size=10G --runtime="$TEST_DURATION" \
        --ioengine=libaio --iodepth="$iodepth" --direct=1 \
        --group_reporting --output="$OUTPUT_DIR/${test_name}.log" \
        --output-format=normal,json >> $LOG_FILE 2>&1

    echo "----------------------------------------" >> $LOG_FILE
}

# 运行测试套件
echo "1. 顺序读写测试" >> $LOG_FILE
run_test "seq_read_1m" "read" "1M" 4
run_test "seq_write_1m" "write" "1M" 4

echo "2. 4K随机读写测试" >> $LOG_FILE
run_test "randread_4k" "randread" "4k" 32
run_test "randwrite_4k" "randwrite" "4k" 32

echo "3. 混合读写测试" >> $LOG_FILE
run_test "mixed_70r30w_4k" "randrw" "4k" 32

echo "4. 不同队列深度测试" >> $LOG_FILE
for depth in 1 4 8 16 32 64; do
    run_test "randread_4k_depth${depth}" "randread" "4k" $depth
done

echo "测试完成!结果保存在: $OUTPUT_DIR" | tee -a $LOG_FILE
echo "详细报告: $LOG_FILE"
结果分析脚本
#!/bin/bash
# fio结果分析脚本
RESULTS_DIR="/var/log/fio_tests"
OUTPUT_FILE="/tmp/fio_summary_$(date +%Y%m%d).csv"

echo "Test Name,Read BW(MB/s),Write BW(MB/s),Read IOPS,Write IOPS,Read Latency(ms),Write Latency(ms)" > $OUTPUT_FILE

for logfile in $RESULTS_DIR/*.log; do
    if [ -f "$logfile" ]; then
        TEST_NAME=$(basename "$logfile" .log)

        # 从日志文件中提取关键指标(简化版)
        READ_BW=$(grep -A1 "READ:" "$logfile" | grep "bw=" | awk -F'=' '{print $2}' | awk '{print $1}')
        WRITE_BW=$(grep -A1 "WRITE:" "$logfile" | grep "bw=" | awk -F'=' '{print $2}' | awk '{print $1}')

        READ_IOPS=$(grep -A1 "READ:" "$logfile" | grep "iops=" | awk -F'=' '{print $2}' | awk '{print $1}')
        WRITE_IOPS=$(grep -A1 "WRITE:" "$logfile" | grep "iops=" | awk -F'=' '{print $2}' | awk '{print $1}')

        READ_LAT=$(grep -A1 "READ:" "$logfile" | grep "lat" | grep "avg=" | awk -F'=' '{print $2}' | awk '{print $1}')
        WRITE_LAT=$(grep -A1 "WRITE:" "$logfile" | grep "lat" | grep "avg=" | awk -F'=' '{print $2}' | awk '{print $1}')

        echo "$TEST_NAME,$READ_BW,$WRITE_BW,$READ_IOPS,$WRITE_IOPS,$READ_LAT,$WRITE_LAT" >> $OUTPUT_FILE
    fi
done

echo "分析完成!结果已保存到: $OUTPUT_FILE"
echo ""
echo "=== 性能概览 ==="
cat $OUTPUT_FILE | column -t -s,

常见问题与解决方案

原因:libaio库未安装或内核不支持。

解决方案:

# 安装libaio库
# Ubuntu/Debian
sudo apt-get install libaio1 libaio-dev

# RHEL/CentOS
sudo yum install libaio libaio-devel

# 或者使用其他I/O引擎
--ioengine=sync   # 同步I/O
--ioengine=posixaio  # POSIX异步I/O

# 检查内核是否支持
lsmod | grep aio
cat /proc/sys/fs/aio-max-nr

直接测试块设备:

# 使用设备文件,不要挂载
# 首先卸载设备
sudo umount /dev/sdb

# 直接测试整个磁盘
fio --name=disk_test --filename=/dev/sdb --rw=randread \
    --bs=4k --size=100% --runtime=60 --ioengine=libaio \
    --direct=1 --group_reporting

# 注意:
# 1. 使用 --size=100% 测试整个设备
# 2. 确保设备上没有重要数据
# 3. 可能需要使用--offset参数跳过某些区域

可能原因和优化方法:

  1. 增加队列深度: --iodepth=32 或更高
  2. 增加并发任务: --numjobs=4
  3. 使用异步I/O: --ioengine=libaio
  4. 绕过缓存: --direct=1
  5. 减少块大小: --bs=4k(随机测试)
  6. 检查磁盘调度器:
    cat /sys/block/sdb/queue/scheduler
    # 对于SSD,使用noop或deadline
    echo noop > /sys/block/sdb/queue/scheduler
  7. 检查文件系统:某些文件系统可能影响性能
  8. 硬件限制:检查磁盘实际规格

最佳实践

推荐做法
  • 测试前备份重要数据
  • 在未使用的磁盘或分区上进行测试
  • 使用--direct=1绕过缓存获得真实磁盘性能
  • 测试时间足够长(至少30-60秒)以获得稳定结果
  • 多次测试取平均值
  • 使用任务文件管理复杂测试场景
  • 保存测试结果用于后续比较
  • 测试前后检查磁盘健康状态
避免的做法
  • 不要在已挂载的生产系统上测试
  • 不要忽略--direct参数(可能导致缓存影响结果)
  • 测试时间不要太短(至少30秒)
  • 不要使用过小的测试文件(小于磁盘缓存)
  • 不要忘记记录测试参数和结果
  • 不要在RAID重建期间测试
  • 不要忽略系统其他负载的影响
  • 不要用有数据的磁盘进行写测试

相关工具

bonnie++

文件系统性能基准测试

iozone

文件系统基准测试工具

hdparm

磁盘读取性能测试

dd

简单的磁盘复制和测试