Files
diskTest/fio_test.sh

144 lines
6.8 KiB
Bash
Executable File

#!/bin/bash
# ==============================================================================
# 脚本名称:fio_test.sh
# 功能:测试存储设备的随机/顺序性能(支持读/写/混合读写,6种测试类型)
# 参数(测试类型):
# 0 = 随机读 (randread) | 1 = 随机写 (randwrite)
# 2 = 混合随机读写 (randrw) | 3 = 顺序读 (read)
# 4 = 顺序写 (write) | 5 = 混合顺序读写 (rw/readwrite)
# 注意事项:
# 1. 测试设备路径一定要手动修改准确,避免造成数据损失(可使用lsblk命令查看挂载设备)
# 2. 写测试(1/2/4/5)会覆盖设备数据(裸设备清除所有数据,文件系统文件覆盖内容)
# 3. 使用--direct=1绕过OS缓存(无法完全绕过硬盘自身缓存)
# 4. 需root权限执行
# ==============================================================================
# -------------------------- 用户配置区(按需修改)--------------------------
DEVICE="/dev/sda" # 重要选项提示!!!! 测试设备路径(裸设备)或文件路径(文件系统)
TEST_TYPE=$1 # 测试类型
TEST_SIZE="10G" # 测试数据量(可选项:不配置为裸设备详见注意事项2,提示:SSD缓存为几百MB到几GB,HDD缓存仅几MB)
# 块大小配置(随机用小block,顺序用大block)
BS_RANDOM="4k" # 随机测试(0/1/2)块大小(4k模拟数据库)
BS_SEQ="128k" # 顺序测试(3/4/5)块大小(128k发挥带宽)
# 队列深度与线程数(HDD:低iodepth/线程,SSD:高iodepth/线程)
IODepth_RANDOM=16 # 随机测试队列深度(HDD:8-32,SSD:64-256)
IODepth_SEQ=32 # 顺序测试队列深度(HDD:16-64,SSD:64-128)
NumJobs=4 # 并发线程数(建议CPU核心数×1,HDD用2-4,SSD用8-16)
Runtime=300 # 测试时长(秒,≥180秒)
# -------------------------- 前置检查----------------------------------------
# 检查root权限
if [ "$UID" -ne 0 ]; then
echo "请用root运行"
exit 1
fi
# 检查fio是否安装
if ! command -v fio &> /dev/null; then
echo "错误:未找到fio工具,请先使用包管理器安装如:(oma install fio 或 apt install fio)"
exit 1
fi
# -------------------------- 参数检查与初始化 ------------------------------
# 查看当前所有挂载设备
echo "当前所有挂载设备:"
lsblk -ln -o NAME | awk '{print "/dev/"$1}' | while read dev; do
mnt=$(findmnt -no TARGET "$dev" 2>/dev/null | head -n 1)
echo "设备: $dev -> 挂载点: ${mnt:-未挂载}"
done
# 获取输入的测试设备
while true; do
read -rp "请输入测试设备路径(默认 /dev/sda): " DEVICE
DEVICE=${DEVICE:-/dev/sda}
# 校验路径格式
if [[ "$DEVICE" != /* ]]; then
echo "错误:必须使用绝对路径"
continue
fi
# 检查设备是否存在
if [ ! -e "$DEVICE" ]; then
echo "错误:设备$DEVICE 不存在"
continue
if [ -n "$(ls -A "$DEVICE" 2>/dev/null)" ]; then
read -rp "警告:目标非空!请确认是否继续?[y/n] " confirm
if [[ "$confirm" =~ ^[Nn]$ ]]; then
continue
fi
fi
fi
break
done
# 提取设备名
DEV_NAME=$(basename "$DEVICE")
# 检查输入的测试参数
echo "参数(测试类型):"
echo "0 = 随机读 (randread) | 1 = 随机写 (randwrite)"
echo "2 = 混合随机读写 (randrw) | 3 = 顺序读 (read)"
echo "4 = 顺序写 (write) | 5 = 混合顺序读写 (rw/readwrite)"
while true; do
read -rp "请输入测试类型: " TEST_TYPE
case $TEST_TYPE in
0) RW_MODE="randread"; BS="$BS_RANDOM"; IODEPTH="$IODepth_RANDOM"; JOB_NAME="randread_test" ; echo "开始随机读测试 (randread, ${BS_RANDOM}块)"; break ;;
1) RW_MODE="randwrite"; BS="$BS_RANDOM"; IODEPTH="$IODepth_RANDOM"; JOB_NAME="randwrite_test" ;echo "开始随机写测试 (randwrite, ${BS_RANDOM}块)"; break ;;
2) RW_MODE="randrw"; BS="$BS_RANDOM"; IODEPTH="$IODepth_RANDOM"; JOB_NAME="randrw_test" ;echo "开始混合随机读写测试 (randrw, ${BS_RANDOM}块)"; break ;;
3) RW_MODE="read"; BS="$BS_SEQ"; IODEPTH="$IODepth_SEQ"; JOB_NAME="seq_read_test" ;echo "开始顺序读测试 (read, ${BS_SEQ}块)"; break ;;
4) RW_MODE="write"; BS="$BS_SEQ"; IODEPTH="$IODepth_SEQ"; JOB_NAME="seq_write_test" ;echo "开始顺序写测试 (write, ${BS_SEQ}块)"; break ;;
5) RW_MODE="rw"; BS="$BS_SEQ"; IODEPTH="$IODepth_SEQ"; JOB_NAME="seq_rw_test" ;echo "开始混合顺序读写测试 (rw, ${BS_SEQ}块)"; break ;;
*) echo "错误:无效测试类型 '$TEST_TYPE'(必须为0-5)"; continue ;;
esac
done
#日志文件名
LOG_FILE="${DEV_NAME}_${RW_MODE}_$(date +%Y%m%d_%H%M%S).log"
# -------------------------- 跳过缓存区的解决方案--------------------------
# 1. fio的--direct=1:绕过操作系统页缓存(Page Cache)
# 2. 无法完全跳过硬盘自身缓存(如HDD的板载DRAM缓存、SSD的SLC缓存),但可通过以下方法减少影响:
# - 数据量 > 硬盘缓存:测试时数据量远大于缓存,使缓存饱和
# -------------------------- 安全确认 --------------------------
# 写测试类型:1(随机写)、2(混合随机读写)、4(顺序写)、5(混合顺序读写)
if [[ "$TEST_TYPE" =~ [1245] ]]; then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "警告:此测试会覆盖 $DEVICE 的所有数据(不可恢复)!"
echo "请确保设备上无重要数据,或已提前备份!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
read -p "确认继续?(输入 YES 继续,其他键取消): " confirm
if [ "$confirm" != "YES" ]; then
echo "测试已取消"
exit 0
fi
fi
# -------------------------- 执行测试 --------------------------
echo "开始测试:类型=$TEST_TYPE($RW_MODE), 设备=$DEVICE, 块大小=$BS"
echo "队列深度=$IODEPTH, 线程数=$NumJobs, 时长=${Runtime}秒, 测试量=$TEST_SIZE "
echo "日志文件:$LogFile"
# 构建fio命令(基础参数)
FIO_CMD=(
"--filename=$DEVICE" # 测试设备(无转义引号,直接传递)
"--direct=1" # 绕过OS缓存
"--rw=$RW_MODE" # 读写模式
"--bs=$BS" # 块大小
"--iodepth=$IODEPTH" # 队列深度
"--numjobs=$NumJobs" # 线程数
# "--runtime=$Runtime" # 测试时长
"--size=$TEST_SIZE" # 测试数据量
"--ioengine=libaio" # 异步引擎
"--group_reporting" # 汇总结果
"--status-interval=1" # 实时刷新
"--eta=always" # 显示剩余时间
"--name=$JOB_NAME" # 任务名
"--output=$LOG_FILE" # 日志文件
# "--minimal" # 极简输出
)
# 执行命令:
fio "${FIO_CMD[@]}"
echo "测试完成!日志文件:$LogFile"