强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Sysbench 完全指南 / 第八章:文件 I/O 测试

第八章:文件 I/O 测试

8.1 概述

文件 I/O 性能直接影响数据库、日志系统、大数据处理等场景的整体性能。Sysbench 的 fileio 测试模块可以测量存储设备的顺序读写、随机读写性能,是服务器选型和存储评估的必备工具。

8.1.1 适用场景

场景测试内容
服务器选型对比 SSD vs HDD、NVMe vs SATA
文件系统对比ext4 vs xfs vs btrfs vs zfs
RAID 方案评估RAID 0 / 1 / 5 / 10 性能对比
云存储评估EBS / 云盘 / NAS 性能对比
I/O 调度器对比mq-deadline / bfq / none / kyber
内核参数调优预读大小、队列深度等

8.2 测试模式

8.2.1 可用的 I/O 测试模式

模式说明用途
seqwr顺序写(Sequential Write)日志写入、备份、数据导入
seqrd顺序读(Sequential Read)数据扫描、备份恢复
seqrewr顺序重写(Sequential Rewrite)文件原地更新
rndrd随机读(Random Read)数据库查询、随机访问
rndwr随机写(Random Write)数据库写入、随机更新
rndrw随机读写混合(Random Read/Write)OLTP 数据库、混合负载

8.2.2 测试流程

文件 I/O 测试遵循三阶段流程:

prepare → run → cleanup
   │        │        │
   │        │        └── 删除测试文件
   │        └─────────── 执行 I/O 测试
   └──────────────────── 创建测试文件
# 1. 准备(创建测试文件)
sysbench fileio --file-total-size=10G prepare

# 2. 运行测试
sysbench fileio --file-total-size=10G --file-test-mode=rndrw --time=60 run

# 3. 清理(删除测试文件)
sysbench fileio --file-total-size=10G cleanup

重要prepare 阶段会创建与 --file-total-size 等大的文件。确保目标目录有足够空间!


8.3 文件 I/O 选项

8.3.1 核心选项

选项默认值说明
--file-test-moderndrw测试模式:seqwr/seqrd/seqrewr/rndrd/rndwr/rndrw
--file-total-size2G测试文件总大小
--file-num128测试文件数量
--file-block-size16KI/O 块大小
--file-io-modesyncI/O 模式:sync(同步)/ async(异步)
--file-async-backlog128异步 I/O 的并发请求数
--file-extra-flags(无)额外的文件打开标志
--file-fsync-freq100每 N 次写操作后执行 fsync(0 = 不 fsync)
--file-fsync-all[=on/off]off每次写操作后都 fsync
--file-fsync-end[=on/off]on测试结束时 fsync
--file-merged-requests0合并相同位置的 I/O 请求(0 = 不合并)
--file-rw-ratio1.5随机读写模式下的读/写比例

8.3.2 I/O 模式详解

同步 I/O (sync):
  请求1 → 等待完成 → 请求2 → 等待完成 → ...
  优点: 延迟准确
  缺点: 并发度低

异步 I/O (async, io_uring/libaio):
  请求1 ──→ 发出
  请求2 ──→ 发出    (并发)
  请求3 ──→ 发出
  等待全部完成
  优点: 高并发、高吞吐
  缺点: 需要内核支持

8.4 顺序读写测试

8.4.1 顺序写测试

# 准备测试文件
sysbench fileio --file-total-size=20G --file-num=16 prepare

# 顺序写测试
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=seqwr \
  --file-block-size=1M \
  --file-io-mode=sync \
  --file-fsync-freq=1000 \
  --threads=1 \
  --time=120 \
  run

8.4.2 顺序读测试

# 顺序读测试(文件已在 prepare 阶段创建)
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=seqrd \
  --file-block-size=1M \
  --file-io-mode=sync \
  --threads=1 \
  --time=120 \
  run

8.4.3 顺序重写测试

sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=seqrewr \
  --file-block-size=1M \
  --threads=1 \
  --time=120 \
  run

8.4.4 多线程顺序读写

# 使用 4 个线程并行顺序读
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=seqrd \
  --file-block-size=1M \
  --threads=4 \
  --time=120 \
  run

注意:顺序 I/O 测试通常使用单线程或少量线程,因为顺序操作本身就是串行化的。多线程顺序 I/O 可能产生磁盘寻道,退化为随机 I/O。


8.5 随机读写测试

8.5.1 随机读测试

sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=rndrd \
  --file-block-size=4K \
  --file-io-mode=sync \
  --threads=32 \
  --time=120 \
  run

8.5.2 随机写测试

sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=rndwr \
  --file-block-size=4K \
  --file-fsync-freq=100 \
  --threads=32 \
  --time=120 \
  run

8.5.3 随机读写混合测试

# 默认读写比例 1.5:1
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=rndrw \
  --file-block-size=4K \
  --file-rw-ratio=1.5 \
  --file-fsync-freq=100 \
  --threads=32 \
  --time=120 \
  --histogram \
  run

# 自定义读写比例 7:3(更接近 OLTP 读多写少场景)
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=rndrw \
  --file-block-size=4K \
  --file-rw-ratio=2.33 \
  --threads=32 \
  --time=120 \
  run

8.5.4 异步 I/O 测试

# 使用 Linux AIO(libaio)
sysbench fileio \
  --file-total-size=20G \
  --file-num=16 \
  --file-test-mode=rndrd \
  --file-block-size=4K \
  --file-io-mode=async \
  --file-async-backlog=128 \
  --threads=32 \
  --time=120 \
  run

# 注意:需要内核支持 AIO
# 检查方法: ls /dev/aio 或 cat /proc/sys/fs/aio-max-nr

8.6 输出结果解读

8.6.1 示例输出

File operations:
    reads/s:                      45678.90      ← 每秒读操作数
    writes/s:                     30452.60      ← 每秒写操作数
    fsyncs/s:                      3045.26      ← 每秒 fsync 次数

Throughput:                         吞吐量
    read, MiB/s:                  178.43        ← 读吞吐量(MB/s)
    written, MiB/s:               118.96        ← 写吞吐量(MB/s)

General statistics:                 总体统计
    total time:                          120.0024s
    total number of events:              9487654

Latency (ms):                       延迟
         min:                                    0.01
         avg:                                    0.40
         max:                                   12.34
         95th percentile:                        0.62
         sum:                                 3798.12

Threads fairness:
    events (avg/stddev):           296489.1875/1234.56
    execution time (avg/stddev):   119.9992/0.00

8.6.2 关键指标

指标含义SSD 典型值HDD 典型值
reads/sIOPS(读)10K-500K100-200
writes/sIOPS(写)10K-300K100-200
read, MiB/s吞吐量(读)500-7000 MB/s100-200 MB/s
written, MiB/s吞吐量(写)400-5000 MB/s80-180 MB/s
avg latency平均延迟0.05-0.5 ms5-15 ms
95th percentileP95 延迟0.1-1 ms10-20 ms

8.7 综合测试方案

8.7.1 完整存储性能评估

#!/bin/bash
# full_fileio_benchmark.sh - 完整存储性能评估

TEST_DIR="/data/sysbench_test"  # 测试目录(建议使用独立分区)
FILE_SIZE="20G"
FILE_NUM=16
DURATION=120
RESULT_DIR="./fileio_results_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$RESULT_DIR"

cd "$TEST_DIR"

# 创建测试文件
echo ">>> Preparing test files..."
sysbench fileio --file-total-size=$FILE_SIZE --file-num=$FILE_NUM prepare

# 测试列表
declare -A TESTS=(
  ["seqwr"]="顺序写"
  ["seqrd"]="顺序读"
  ["seqrewr"]="顺序重写"
  ["rndrd"]="随机读"
  ["rndwr"]="随机写"
  ["rndrw"]="随机读写"
)

BLOCK_SIZES=("4K" "16K" "64K" "256K" "1M")

for mode in seqwr seqrd seqrewr rndrd rndwr rndrw; do
  for bs in "${BLOCK_SIZES[@]}"; do
    echo ""
    echo ">>> Testing: $mode, block_size=$bs"
    
    if [[ "$mode" == seq* ]]; then
      threads=1
    else
      threads=16
    fi
    
    sysbench fileio \
      --file-total-size=$FILE_SIZE \
      --file-num=$FILE_NUM \
      --file-test-mode=$mode \
      --file-block-size=$bs \
      --file-fsync-freq=100 \
      --threads=$threads \
      --time=$DURATION \
      --histogram \
      --json="$RESULT_DIR/${mode}_${bs}.json" \
      run 2>&1 | tee "$RESULT_DIR/${mode}_${bs}.txt" | \
      grep -E "(reads/s|writes/s|MiB/s|95th|avg:)"
    
    sleep 3
  done
done

# 清理
echo ">>> Cleaning up..."
sysbench fileio --file-total-size=$FILE_SIZE --file-num=$FILE_NUM cleanup

echo ""
echo "Results saved to $RESULT_DIR"

8.7.2 线程扩展性测试

#!/bin/bash
# fileio_threads_test.sh - I/O 线程扩展性测试

FILE_SIZE="20G"
FILE_NUM=16

sysbench fileio --file-total-size=$FILE_SIZE --file-num=$FILE_NUM prepare

for threads in 1 2 4 8 16 32 64 128; do
  echo "=== Threads: $threads ==="
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-num=$FILE_NUM \
    --file-test-mode=rndrw \
    --file-block-size=4K \
    --threads=$threads \
    --time=60 \
    run 2>&1 | grep -E "(reads/s|writes/s|95th)"
  sleep 3
done

sysbench fileio --file-total-size=$FILE_SIZE --file-num=$FILE_NUM cleanup

8.8 文件系统对比测试

8.8.1 对比 ext4 / xfs / btrfs

#!/bin/bash
# fs_comparison.sh - 文件系统对比测试

FS_LIST=("ext4" "xfs" "btrfs")
DEVICE="/dev/sdb"
FILE_SIZE="10G"

for fs in "${FS_LIST[@]}"; do
  echo ""
  echo "==========================================="
  echo "File System: $fs"
  echo "==========================================="
  
  # 格式化(注意:会销毁数据!)
  sudo mkfs.$fs -f $DEVICE
  sudo mkdir -p /mnt/test_$fs
  sudo mount $DEVICE /mnt/test_$fs
  sudo chmod 777 /mnt/test_$fs
  
  # 准备
  cd /mnt/test_$fs
  sysbench fileio --file-total-size=$FILE_SIZE prepare
  
  # 随机读测试
  echo "--- Random Read ---"
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-test-mode=rndrd \
    --file-block-size=4K \
    --threads=32 \
    --time=60 \
    run 2>&1 | grep -E "(reads/s|95th)"
  
  # 随机写测试
  echo "--- Random Write ---"
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-test-mode=rndwr \
    --file-block-size=4K \
    --file-fsync-freq=100 \
    --threads=32 \
    --time=60 \
    run 2>&1 | grep -E "(writes/s|95th)"
  
  # 顺序读测试
  echo "--- Sequential Read ---"
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-test-mode=seqrd \
    --file-block-size=1M \
    --threads=1 \
    --time=60 \
    run 2>&1 | grep -E "(MiB/s|95th)"
  
  # 清理
  sysbench fileio --file-total-size=$FILE_SIZE cleanup
  cd /
  sudo umount /mnt/test_$fs
  
  sleep 5
done

警告:此脚本会格式化磁盘!请勿在生产环境或有数据的磁盘上运行。


8.9 I/O 调度器对比测试

8.9.1 Linux I/O 调度器简介

调度器特点适用场景
mq-deadline合并请求,减少寻道通用,数据库推荐
bfq公平队列,低延迟桌面环境、交互式
kyber双队列(读/写),低延迟快速设备(NVMe)
none / noop不调度,直接发送NVMe SSD

8.9.2 对比脚本

#!/bin/bash
# io_scheduler_test.sh - I/O 调度器对比测试

DEVICE="sda"  # 替换为你的设备名
FILE_SIZE="10G"

# 查看当前调度器
echo "Current scheduler:"
cat /sys/block/$DEVICE/queue/scheduler

# 可用调度器列表
SCHEDULERS=$(cat /sys/block/$DEVICE/queue/scheduler | tr -d '[]' | tr ' ' '\n')

sysbench fileio --file-total-size=$FILE_SIZE prepare

for sched in $SCHEDULERS; do
  echo ""
  echo "=== Scheduler: $sched ==="
  echo $sched | sudo tee /sys/block/$DEVICE/queue/scheduler
  sleep 2
  
  echo "--- Random Read (4K) ---"
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-test-mode=rndrd \
    --file-block-size=4K \
    --threads=32 \
    --time=60 \
    run 2>&1 | grep -E "(reads/s|95th)"
  
  echo "--- Random Write (4K) ---"
  sysbench fileio \
    --file-total-size=$FILE_SIZE \
    --file-test-mode=rndwr \
    --file-block-size=4K \
    --file-fsync-freq=100 \
    --threads=32 \
    --time=60 \
    run 2>&1 | grep -E "(writes/s|95th)"
  
  sleep 3
done

sysbench fileio --file-total-size=$FILE_SIZE cleanup

# 恢复默认调度器
echo "mq-deadline" | sudo tee /sys/block/$DEVICE/queue/scheduler

8.10 块大小对性能的影响

8.10.1 测试不同块大小

#!/bin/bash
# block_size_test.sh

FILE_SIZE="10G"

sysbench fileio --file-total-size=$FILE_SIZE prepare

echo "Block Size,Read IOPS,Read BW(MB/s),Read P95(ms),Write IOPS,Write BW(MB/s),Write P95(ms)"

for bs in "512" "1K" "2K" "4K" "8K" "16K" "32K" "64K" "128K" "256K" "512K" "1M"; do
  # 随机读
  read_result=$(sysbench fileio \
    --file-total-size=$FILE_SIZE --file-test-mode=rndrd \
    --file-block-size=$bs --threads=16 --time=30 run 2>&1)
  read_iops=$(echo "$read_result" | grep "reads/s:" | awk '{print $2}')
  read_bw=$(echo "$read_result" | grep "read, MiB/s:" | awk '{print $3}')
  read_p95=$(echo "$read_result" | grep "95th percentile:" | awk '{print $3}')
  
  # 随机写
  write_result=$(sysbench fileio \
    --file-total-size=$FILE_SIZE --file-test-mode=rndwr \
    --file-block-size=$bs --file-fsync-freq=100 --threads=16 --time=30 run 2>&1)
  write_iops=$(echo "$write_result" | grep "writes/s:" | awk '{print $2}')
  write_bw=$(echo "$write_result" | grep "written, MiB/s:" | awk '{print $3}')
  write_p95=$(echo "$write_result" | grep "95th percentile:" | awk '{print $3}')
  
  echo "$bs,$read_iops,$read_bw,$read_p95,$write_iops,$write_bw,$write_p95"
done

sysbench fileio --file-total-size=$FILE_SIZE cleanup

预期趋势

块大小    IOPS        吞吐量
4K        最高 IOPS   较低吞吐
16K       高 IOPS     中等吞吐
64K       中等 IOPS   较高吞吐
1M        最低 IOPS   最高吞吐
  • 数据库:通常使用 4K-16K 块大小,关注 IOPS
  • 大数据/日志:通常使用 256K-1M 块大小,关注吞吐量

8.11 高级选项

8.11.1 fsync 策略

# 不使用 fsync(最高性能,但不保证数据持久化)
sysbench fileio --file-test-mode=rndwr --file-fsync-freq=0 run

# 每 10 次写入后 fsync
sysbench fileio --file-test-mode=rndwr --file-fsync-freq=10 run

# 每次写入后 fsync(最安全,最低性能)
sysbench fileio --file-test-mode=rndwr --file-fsync-all=on run
fsync 策略场景性能影响
fsync-freq=0纯吞吐量测试无影响
fsync-freq=100一般数据库场景轻微影响
fsync-freq=1金融级持久化显著影响
fsync-all=on最严格持久化严重影响

8.11.2 Direct I/O

# 使用 O_DIRECT 标志(绕过操作系统缓存)
sysbench fileio \
  --file-test-mode=rndrd \
  --file-block-size=4K \
  --file-extra-flags=direct \
  --file-total-size=20G \
  --threads=32 \
  --time=60 \
  run

重要:使用 direct 标志可以避免操作系统文件缓存的影响,获得更准确的磁盘性能数据。但并非所有文件系统都支持 O_DIRECT。

8.11.3 同步模式

# 使用 O_SYNC 标志(每次写入后同步到磁盘)
sysbench fileio \
  --file-test-mode=rndwr \
  --file-block-size=4K \
  --file-extra-flags=sync \
  --file-fsync-freq=0 \
  --file-total-size=20G \
  --threads=16 \
  --time=60 \
  run

# 同时使用 O_DIRECT + O_SYNC
sysbench fileio \
  --file-test-mode=rndwr \
  --file-extra-flags="direct,fsync" \
  --file-total-size=20G \
  --threads=16 \
  --time=60 \
  run

8.12 常见问题

问题 1:测试结果受缓存影响

# 现象:第二次运行比第一次快很多
# 原因:数据被缓存在 OS 页面缓存中

# 解决方案 1:使用 O_DIRECT
sysbench fileio --file-extra-flags=direct ...

# 解决方案 2:测试前清空缓存
echo 3 | sudo tee /proc/sys/vm/drop_caches

# 解决方案 3:使用大于内存的数据集
sysbench fileio --file-total-size=$(free -g | awk '/Mem/{print $2*2}')G ...

问题 2:prepare 阶段耗时很长

# 原因:创建大文件需要时间
# 解决方案:使用 fallocate 快速创建文件
fallocate -l 20G /path/to/test_file

# Sysbench 1.0.20+ 会自动使用 fallocate
# 如果不支持,会回退到写零方式(较慢)

问题 3:测试文件占用空间

# 测试后记得清理
sysbench fileio --file-total-size=20G cleanup

# 手动检查
ls -lh /path/to/test_dir/
du -sh /path/to/test_dir/

8.13 小结

要点说明
测试模式seqwr/seqrd/rndrd/rndwr/rndrw 六种模式
流程prepare → run → cleanup(三步)
关键指标IOPS、吞吐量(MB/s)、延迟(ms)
缓存影响使用 O_DIRECT 或大于内存的数据集
块大小数据库 4K-16K,大数据 256K-1M
调度器NVMe 用 none,SATA SSD 用 mq-deadline

扩展阅读