144 lines
6.8 KiB
Bash
Executable File
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"
|