前些天正好有个外协部门需要利旧,需要根据阿里云的测试流程对新华三的服务器和NVME磁盘进行一下测试,所以把手头的资料整理一下。

2023.05 摄于洛阳·龙门石窟

存储

一开始想写点什么来着,后来发现少数派上的文章写的非常棒,就一并转贴了

数字存储完全指南

  1. 存储设备的诞生与历史
  2. 机械硬盘的原理与参数详解
  3. 固态硬盘的历史、结构与原理
  4. 固态硬盘的参数解读与实际性能
  5. 运行内存都在运行什么?
  6. 理解U盘、内存卡、移动硬盘和手机存储芯片构造

文牍

测试流程

测试用例

测试报告

测试

FIO

简介

FIO是一个用于测试磁盘IOPS性能的工具,可以对本地存储或者远程共享进行压力测试和验证,并能够给出磁盘性能的指标。FIO能够按照随机读、随机写、读写混合等不同IO模式对压测对象进行性能测试。

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 检查是否4k对齐
[root@zhangjiakou ~]# fdisk -lu
Disk /dev/vda: 40 GiB, 42949672960 bytes, 83886080 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: D7B18C8A-605C-42E0-94BF-A4A0B2DE0204

Device Start End Sectors Size Type
/dev/vda1 2048 4095 2048 1M BIOS boot
/dev/vda2 4096 208895 204800 100M EFI System
/dev/vda3 208896 83886046 83677151 39.9G Linux filesystem
# 安装
[root@zhangjiakou ~]# dnf install -y libaio libaio-devel fio
# 测试云盘的随机写IOPS:
fio -direct=1 -iodepth=128 -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/your_device -name=Rand_Write_Testing

# 测试云盘的随机读IOPS:
fio -direct=1 -iodepth=128 -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/your_device -name=Rand_Read_Testing

#测试云盘的顺序写吞吐量:
fio -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=1024k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/your_device -name=Write_PPS_Testing

#测试云盘的顺序读吞吐量:
fio -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=1024k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/your_device -name=Read_PPS_Testing

#测试云盘的随机写时延:
fio -direct=1 -iodepth=1 -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/dev/your_device -name=Rand_Write_Latency_Testing

#测试云盘的随机读时延:
fio -direct=1 -iodepth=1 -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -group_reporting -filename=/dev/your_device -name=Rand_Read_Latency_Testing

参数

参数 说明
direct 表示是否使用direct I/O。默认值:1。值为1:表示使用direct I/O,忽略I/O缓存,数据直写。值为0:表示不使用direct I/O。
iodepth 表示测试时的IO队列深度。例如-iodepth=128表示FIO控制请求中的I/O最大个数为128。
rw 表示测试时的读写策略。您可以设置为:randwrite:随机写。randread:随机读。read:顺序读。write:顺序写。randrw:混合随机读写。
ioengine 表示测试时FIO选择哪种I/O引擎,通常选择libaio,更符合日常应用模式,更多的选择请查阅FIO官方文档。
bs 表示I/O单元的块大小(block size)。默认值:4 KiB。读取和写入的值可以以read、write格式单独指定,其中任何一个都可以为空以将该值保留为其默认值。
size 表示测试文件大小。FIO会将指定的文件大小全部读/写完成,然后才停止测试,除非受到其他选项(例如运行时)的限制。如果未指定该参数,FIO将使用给定文件或设备的完整大小。也可以将大小作为1到100之间的百分比给出。例如指定size=20%,FIO将使用给定文件或设备完整大小的20%空间。
numjobs 表示测试的并发线程数。默认值:1。
runtime 表示测试时间,即FIO运行时长。如果未指定该参数,则FIO会持续将上述size指定大小的文件,以每次bs值为块大小读/写完。
group_reporting 表示测试结果显示模式。如果指定该参数,测试结果会汇总每个进程的统计信息,而不是以不同任务来统计信息。
filename 表示待测试的对象路径,路径可以是云盘设备名称或者一个文件地址。本文中的FIO测试全部是以整盘为测试对象,不含文件系统,即裸盘测试。同时为了避免误测试到其他盘导致数据被破坏,本示例地址为/dev/your_device,请您正确替换。
name 表示测试任务名称,可以随意设定。例如本示例的Rand_Write_Testing。

实例

以下是某次执行测试的实际脚本,需要提前预制安装fio、libaio、nvme、storcli这几个工具。storcli需要到博通网站上下载RPM包。

执行脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/bash
dir=`pwd`

yum install -y fio libaio libaio-devel nvmecli
#rpm -ivh libaio-devel-0.3.109-13.1.alios7.x86_64.rpm
#tar -zxvf fio-fio-2.16.tar.gz
#cd fio-fio-2.16
#./configure
#make
#make install
#cd $dir

controller=`lspci -n|grep -E "1000|9005"`
if [[ ${controller} =~ 1000 ]];
then
# rpm -ivh storcli-007.0504.0000.0000-1.x86_64.rpm
storcli64 show all >> lsi_controller_info.txt
elif [[ ${controller} =~ 9005 ]];
then
./arcconf getconfig 1 ad|grep -iE "controllers found|controller model"|sort -u >> pmc_controller_info.txt
fi

for dev in `ls /sys/block/ |grep -E sd[b-z] & ls /sys/block/ |grep -E "ram*|sd[a-z][a-z]|nvme*"`
do
rootdev=`lsblk |grep ${dev}1|grep /boot`
if [ -z "$rootdev" ];
then
cd $dir
mkdir fiotest-${dev} >/dev/null 2>&1
cd $dir/fiotest-${dev}
if [[ ${dev} =~ nvme ]]
then
nvme format -s 1 /dev/$dev
sleep 5
cp -f ../test-fio-nvme.sh ./ >/dev/null 2>&1
cp -f ../get_result.sh ./ >/dev/null 2>&1
sh test-fio-nvme.sh -p444 $dev &
sleep 5
else
cp -f ../test-fio.sh ./ >/dev/null 2>&1
cp -f ../get_result.sh ./ >/dev/null 2>&1
sh test-fio.sh -p555 $dev &
sleep 5
fi
else
echo "skip $dev ,this is sysdisk..."
fi
done
结果脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#/bin/sh
function get_rw_result()
{
if [ $# -lt 1 ]
then
echo "please input filename:"
exit
else
rw=`cat $1 | grep -i bs | grep -i rw | awk '{print $3}' | awk -F ',' '{print $1}'`
bs=`cat $1 | grep -i bs | grep -i rw | awk '{print $4}' | awk -F '/' '{print $1}'`
depth=`cat $1 | grep -i bs | grep -i rw | awk '{print $6}' | awk -F '=' '{print $2}'`
job=`cat $1 |grep -i starting|awk '{print $2}'`

bw=`cat $1 | grep -i iops | awk -F ',' '{print $2}'`
iops=`cat $1 | grep -i iops | awk -F ',' '{print $3}'`

lat=`cat $1 | grep -i -w lat | grep -i avg | awk -F ',' '{print $3}' | awk '$1=$1'`
unit=`cat $1 | grep -i -w lat | grep -i avg | awk '{print $2}' | cut -b 2-5 | awk '{printf("%s ",$0)}'`

echo ${bs:3},${rw:3},${depth},${job},${bw:4},${iops:6},${lat:4},${unit} >> re.csv
fi
}
function get_mix_result()
{
if [ $# -lt 1 ]
then
echo "please input filename:"
exit
else
#mix_rw=`cat $1 | grep -i bs | grep -i rw | awk '{print $3}' | awk -F ',' '{print $1}'`
mix_rw=`echo $1 | awk -F '_' '{print $1}'`
mix_bs=`cat $1 | grep -i bs | grep -i rw | awk '{print $4}' | awk -F '/' '{print $1}'`

mix_read_bw=`cat $1 | grep -i iops | grep -i read | awk -F ',' '{print $2}' | awk '$1=$1'`
mix_write_bw=`cat $1 | grep -i iops | grep -i write | awk -F ',' '{print $2}' | awk '$1=$1'`

mix_read_iops=`cat $1 | grep -i iops | grep -i read | awk -F ',' '{print $3}' | awk '$1=$1'`
mix_write_iops=`cat $1 | grep -i iops | grep -i write | awk -F ',' '{print $3}' | awk '$1=$1'`

mix_read_lat=`cat $1 | grep -i -w lat | grep -i avg | awk 'NR==1{print}' | awk -F ',' '{print $3}' | awk '$1=$1'`
mix_write_lat=`cat $1 | grep -i -w lat | grep -i avg | awk 'NR==2{print}' | awk -F ',' '{print $3}' | awk '$1=$1'`
mix_unit=`cat $1 | grep -i -w lat | grep -i avg | awk '{print $2}' | cut -b 2-5 | awk '{printf("%s ",$0)}'`

echo ${mix_bs:3},${mix_rw},${mix_read_bw:3},${mix_write_bw:3},${mix_read_iops:5},${mix_write_iops:5},${mix_read_lat:4},${mix_write_lat:4},${mix_unit} >> mix.csv
fi
}

get_rw_result $1

压测脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#/bin/sh
#Author WB-txq457949
#Date 2019/10/04

#Set Runtime & Drive
Test_Device=$2

while true
do
#FIO Test
nvme smart-log /dev/${Test_Device} >>before-smart.log
fio --filename=/dev/${Test_Device} --ioengine=libaio --direct=1 --thread=1 --numjobs=1 --iodepth=16 --rw=randread --bs=16k --runtime=12h --log_avg_msec=1000 --write_lat_log=16k_1job_16iodepth_randread --write_iops_log=iops_16k_1job_16iodepth_randread --size=100% --group_reporting --name=mytest >randread.rec

fio --filename=/dev/${Test_Device} --ioengine=libaio --direct=1 --thread=1 --numjobs=1 --iodepth=16 --rw=randwrite --bs=16k --runtime=12h --log_avg_msec=1000 --write_lat_log=16k_1job_16iodepth_randwrite --write_iops_log=iops_16k_1job_16iodepth_randwrite --size=100% --group_reporting --name=mytest > randwrite.rec

fio --filename=/dev/${Test_Device} --ioengine=libaio --direct=1 --thread=1 --numjobs=1 --iodepth=16 --rw=randrw --rwmixwrite=30 --bs=16k --runtime=6d --log_avg_msec=1000 --write_lat_log=16k_1job_16iodepth_mixreadwrite --write_iops_log=iops_16k_1job_16iodepth_mixreadwrite --size=100% --group_reporting --name=mytest > mixreadwrite.rec

nvme smart-log /dev/${Test_Device} >>affter-smart.log

echo "BS,Modes,Iodepth,numjobs,BW,IOPS,Latency,Unit" > re.csv
#echo "Mix_BS,Mix_Mode,Read_BW,Write_BW,Read_IOPS,Write_IOPS,Read_Latency,Write_Latency,Lat_Unit" > mix.csv

for result in `ls *.rec`
do
sh get_result.sh $result
done
done