Top
FIO 下载地址
Github Download -- FIO
Kernel Download -- FIO
FIO 安装
./configure --enable-gfio # 只有加这个参数才能编译安装gfio
make fio
make gfio
make install
参数解析
--readwrite=${RW} # 表示测试类型; 分顺序读 -rw=read ,随机读 -rw=randread,顺序写 -rw=write,随机写-rw=randwrite ,混合随机读写模式 -rw=randrw
--bs=4k # 表示 I/O block大小,默认是4k; 也可指定为 --blocksize=4k
--runtime=300s # 指定在多少秒后停止进程。如果未指定该参数,fio将执行至指定的文件读写完全完成
--numjobs=16 # 指定job的克隆数(线程)
--iodepth=64 ${PARA_LINE} # 表示 I/O 队列深度; 如果ioengine采用异步方式,该参数表示一批提交保持的io单元数
--filename=/dev/${DEV_LIST} # 表示要测试的裸设备(硬盘或分区); 切勿在系统分区做测试,会破坏系统分区,而导致系统崩溃。若一定要测试系统分区较为安全的方法是:在根目录下创建一个空目录,在测试命令中使用directory参数指定该目录,而不使用filename参数
--name=${DEV_LIST}_${RW}_4k_16_64 # 定义测试任务名称。
-end_fsync=0
--group_reporting # 定义测试结果显示模式,group_reporting 表示汇总每个进程的统计信息,而非以不同 job汇总展示信息
-direct=1, # 定义是否使用direct IO,可选值如下:值为0,表示使用buffered IO;值为1,表示使用 direct IO; 测试过程绕过机器自带的buffer。使测试结果更真实;
-ioengine=${IO_ENGINE} # 指定I/O 处理处理模型, libaio指的是异步模式,如果是同步就要用sync, 同步IO一次只能发出一个IO请求,
-thread # 指定创建线程的方式,将使用pthread_create来创建线程;另一种是fork创建进程。进程的开销比线程要大,一般都采用thread测试
-time_based # file若已被完全读写或写完,强制执行完runtime规定的时间。它是通过循环执行相同的负载来实现的,与runtime相对应
-buffer_compress_percentage=0 # 设定缓冲区数据的压缩级别
-invalidate=1
-norandommap
-randrepeat=0 # 对于随机IO负载,配置生成器的种子,使得路径是可以预估的,使得每次重复执行生成的序列是一样的, 不设置的话, 会影响seqwrite,randwrite,randread,
-exitall
-size=${FILE_SIZE} # 定义测试IO操作的数据量,若未指定runtime这类参数,fio会将指定大小的数据量全部 读/写完成,然后才停止测试。该参数的值,可以是带单位的数字,比如size=10G,表示读/写的数据量为10GB;也可是百分数,比如size=20%,表示读/写的数据量占该设备总文件的20%的空间。建议测试数据量为内存两倍大,尽量避免缓存影响
--offset_increment=100G # 表示跳过指定的数据量大小,
--loop # 定义硬盘执行的圈数, loops与runtime是两个不能同时存在的两个参数
-ramp_time # 设定在记录任何性能信息之前要运行特定负载的时间。这个用来等性能稳定后,再记录日志结果,因此可以减少生成稳定的结果需要的运行时间
--output=txt,pdf,html # 输出的文件名
--output-format:# 定义日志输出格式(normal',terse', json', orjson+')
--rwmixwrite # 在混合读写模式下, 写所占用的百分比
--rwmixread # 在混合读写模式下, 读所占用的百分比
-lockmem # 表示锁定内存的大小
--hugepage-size=int # 设置大页数量
zero_buffers # 用0初始化系统buffer。
nrfiles=8 # 每个进程生成文件的数量。
nrfiles=8 # 每个进程生成文件的数量
-cpus_allowed=0,5,8-15 # 绑核
-cpus_allowed_policy=split # 设置fio分配cpu的策略
# shared # 所有作业将共享指定的CPU集
# split # 每个作业将从CPU集中获得一个唯一的CPU
-numa_cpu_nodes=0 # 设置此作业在指定NUMA节点的cpu上运行, 参数允许使用逗号分隔的cpu编号列表, '0-3' or 'all', 可用策略为:`default', `prefer', `bind', `interleave' or `local'
-uid='int' # 用户 ID
-gid='int' # 组 ID
--rate_iops=500 # 锁定IOPS
--rate=100m # 锁定带宽
################################ 测试报告
--write_bw_log=str # <--name参数值>_bw.<线程ID>.log, 同一个 Fio , 针对每个 线程都会生成一个文件
--write_lat_log=str # <--name参数值>_lat.<线程ID>.log, 同一个 Fio , 针对每个 线程都会生成一个文件
--write_iops_log=str # <--name参数值>_iops.<线程ID>.log, 同一个 Fio , 针对每个 线程都会生成一个文件
--bsrange=512-2048 # 提定数据块的大小范围
--bssplit=4k/50:8k/20:16k/10:32k/20 # 对块大小进行更细粒度的控制,顺序不重要。如果百分比为空,fio将均匀地填充剩余的值,比如:4k/50:1k/:32k/ ;
若您希望工作负载具有50%的2k读取和50%的4k读取,同时具有90%的4k写入和10%的8k写,
比如: bssplit=2k/50:4k/50,4k/90:8k/10
--blocksize_range # 指定了block size的范围,相当于动态的block size
-directory= # 文件创建的目录,当对NFS文件系统进行测试时,该参数可以指定客户端NFS挂载的目录
# 对 BW 影响显著的参数
--bs=4k
--numjobs=2
--iodepth=32
-direct=1
--offset_increment=100G
-ioengine=libaio | psync
-thread
当 SSD 的 scheduler 为 mq-deadline 时, randread 的 IOPS 会高些
当 SSD 的 scheduler 为 none 时, randwrite 的 IOPS 会高些
结果分析
BW: 基于样本的带宽统计
IOPS : # IOPS
lat # I / O完成延迟的分布; (nsec/usec/msec)
clat # 完成延迟。 与板条同名,表示从提交到完成I / O件的时间。 对于同步I / O,clat通常等于(或非常接近)0;
slat # 提交延迟(min为最小值,max为最大值,avg为平均值,stdev为标准偏差)。 这是提交I / O所花费的时间
cpu # CPU使用率
IO depths # I / O深度在整个工作周期中的分布
util # 磁盘利用率。 值为100%表示我们使磁盘一直处于繁忙状态,而50%的磁盘将有一半的时间处于空闲状态
自带图形化工具
# 按照依赖包
yum install -y gnuplot
fio_generate_plots 接受的唯一参数就是这个日志文件名的prefix
单位换算
Mbit/s的意思是每秒中传输10^6 bit的数据,也写成Mbps
MB/s的意思是每秒中传输10^6 byte的数据
MiB/s的意思是每秒中传输2^20 byte的数据,不太常用
PS:所以如果一个运营商声称自己的传输带宽是1 Mbps
MB/s=MiB/s *1.024
Mbit/s * 8 = MB/s
Mbit/s = MiB/s * 0.1192
GB=0.9313225746GiB
相关命令
# SATA, SAS 盘安全擦除
hdparm --user-master u --security-set-pass PASSWD /dev/sdx # 获取权限
hdparm --user-master u --security-erase PASSWD /dev/sdx # 执行安全擦除
##### HDD
1. 关闭缓存
sdparm -s WCE=0 --save /dev/sd$i : 关闭SAS HDD 缓存
hdparm -W 0 /dev/sd$i : 关闭 SATA HDD 缓存
2. 修改算法
for i in {a..l};do echo mq-deadline > /sys/block/sd$i/queue/scheduler;done
3. 收集所有盘信息
4. 修改脚本,注意一下几点 :
threads = 2
iodepth : 32
--offset_increment=100G
5. 测试
nohup &>/dev/null bash run_parallel_hdd.sh &
## 获取 缓存信息
sdparm -g WCE /dev/sda # 获取 SAS HDD 缓存
hdparm -W 0 /dev/sd$i # 获取 SATA HDD 缓存
# 查看盘列表信息
lsscsi -g -s -k
lsblk -p
nvme list
结果格式化
awk '/IOPS/{split($2, iops_len, "=");split($4, bw_li, ")");split(bw_li[1], bw_li_li, "(");printf("%s,--- %s\n", bw_li_li[2], iops_len[2]); }' hdd_sda_read.log
awk '/IOPS/{
split($2, iops_li, "=")
split($4, bw_li, ")")
gsub(",", "", iops_li[2])
bw=substr(bw_li[1], 2)
printf("%s %s\n", iops_li[2], bw)
}' hdd_sda_read.log
# 获取 IOPS 和 BW
awk '/IOPS/{split($2, iops_li, "=");split($4, bw_li, ")");gsub(",", "", iops_li[2]);bw=substr(bw_li[1], 2);printf("%-10s %-10s\n", iops_li[2], bw);}' hdd_sda_read.log
# 获取 IOPS 和 BW , 并自动处理 带宽的单位,统一换算为 MB/s
awk '/IOPS=/{split($2, iops_li, "=");split($4, bw_li, ")");gsub(",", "", iops_li[2]);bw=substr(bw_li[1], 2);end=match(bw, "kB/s|MB/s|GB/s", bws);bw_num=substr(bw, 1, end - 1);if (bws[0] == "kB/s"){bw_num/=1000;};if (bws[0] == "GB/s"){bw_num*=1000;};printf("%-10s %-10s\n", iops_li[2], bw_num"MB/s");}' hdd_sdm_randread.log
# 获取 设备名, Block , Threads, IoDepth 大小
cat hdd_sda_read.log | grep pid= | awk '{print $1}' | sed 's/.$//g' | awk 'BEGIN{FS="_"}{printf("%-9s %-5s %-5s %-5s\n",$1,$2,$3,$4); }'
# 格式化 获取 设备名, Block , Threads, IoDepth
awk '/pid=/{ff=$1;gsub(":","",ff);split(ff,li,"_");printf("%-10s %-10s %-6s %-6s %-6s\n", li[1],li[2],li[3],li[4],li[5]);'} hdd_sda_read.log
# find 遍历目录下文件,但不打印当前目录文件本身
for fff in `find ./hdd_fio_log_TOSHIBA_HDD_SATA_8T/*`; do echo $fff ; done
# find 遍历目录下文件,但不打印当前目录文件本身,然后格式化输出每个FIO 的 IOPS 和 BW 数据
for fff in `find ./hdd_fio_log_TOSHIBA_HDD_SATA_8T/*`; do printf "%s\n" ${fff}; awk '/IOPS=/{split($2, iops_li, "=");split($4, bw_li, ")");gsub(",", "", iops_li[2]);bw=substr(bw_li[1], 2);end=match(bw, "kB/s|MB/s|GB/s", bws);bw_num=substr(bw, 1, end - 1);if (bws[0] == "kB/s"){bw_num/=1000;};if (bws[0] == "GB/s"){bw_num*=1000;};printf("%-10s %-10s\n", iops_li[2], bw_num"MB/s");}' $fff ; done
# 过滤出有 IOPS 和时延数据的行,然后将其每个FIO 的数据合并为 一行
awk '/IOPS=|clat.*avg=/{if($0 ~ "IOPS=")ORS="";else ORS="\n"; print $0;}' hdd_sda_read.log
# 格式化输出一个文件中所有FIO程序的的 IOPS, BW , 时延数据,也可根据需要稍微修改脚本,使其所有数据输出在一行,其中每 3 个数据为一组(IOPS , BW, CLAT),且 BW 的单位默认为 MB/s, CLAT 的单位为 msec(毫秒)
awk '/IOPS=|clat.*avg=/{
if($0 ~ "IOPS="){
ORS=""
split($2, iops_li, "=")
split($4, bw_li, ")")
gsub(",", "", iops_li[2])
bw=substr(bw_li[1], 2)
end=match(bw, "kB/s|MB/s|GB/s", bws)
bw_num=substr(bw, 1, end - 1)
if (bws[0] == "kB/s"){bw_num/=1000;}
if (bws[0] == "GB/s"){bw_num*=1000;}
printf("%-10s %-10s ", iops_li[2], bw_num"MB/s")}
else {
ORS="\n"
cunit=substr($2,2,4)
sub(",","",$5)
sub("avg=","",$5)
if (cunit == "usec"){$5/=1000}
printf("%-10s",$5)}
}' hdd_sda_read.log
# 结果输出格式如下:
==========================================
16.8k 68.0MB/s 3.79792
3734 245MB/s 17.14
946 248MB/s 67.62
253 266MB/s 126.23
242 254MB/s 263.88
# V2 格式化输出一个文件中所有FIO程序的的 IOPS, BW , 时延数据,也可根据需要稍微修改脚本,使其所有数据输出在一行,其中每 3 个数据为一组(IOPS , BW, CLAT),且 BW 的单位默认为 MB/s, CLAT 的单位为 msec(毫秒)
awk '/IOPS=|clat.*avg=/{
if($0 ~ "IOPS="){
ORS=""
split($2, iops_li, "=")
split($4, bw_li, ")")
gsub(",", "", iops_li[2])
if(iops_li[2]~/k/){iops_li[2]*=1000}
bw=substr(bw_li[1], 2)
end=match(bw, "kB/s|MB/s|GB/s", bws)
bw_num=substr(bw, 1, end - 1)
if (bws[0] == "kB/s"){bw_num/=1000;}
if (bws[0] == "GB/s"){bw_num*=1000;}
printf("%-10s %-10s %4s ", iops_li[2], bw_num, "MB/s")}
else {
ORS="\n"
cunit=substr($2,2,4)
sub(",","",$5)
sub("avg=","",$5)
if (cunit == "msec"){$5*=1000}
if (cunit == "nsec"){$5/=1000}
printf("%-10s %4s\n",$5, "usec")}
}' $1
# 结果输出格式如下:
==========================================
205k 841 MB/s 37.2867 usec
82.0k 336 MB/s 10.816 usec
103k 843 MB/s 75.9789 usec
206k 842 MB/s 154.23 usec
207k 847 MB/s 4952.51 usec
206k 843 MB/s 620.07 usec
206k 846 MB/s 1238.31 usec
206k 845 MB/s 9926.19 usec
207k 846 MB/s 1237.85 usec
# 对 Fio 文件中测试文件(即测试设备文件)的提取
awk -F':' '/util=/{print $1}' hdd_sdd_randread.log | xargs
# 对 Fio 文件中测试模式的提取
cat hdd_sdd_randwrite.log | grep rw= | sed '/rw=/s/.*rw=\(.*\), bs=.*/\1/g'
sed '/rw=/s/.*rw=\(.*\), bs=.*/\1/gp' -n ssd_nvme2n1_randread.log
awk -F'rw=' '/rw=/{split($2,li,",");print li[1];}' hdd_sdd_randread.log | xargs
# 对 Fio 文件中测试 ioengine 的提取
awk -F'ioengine=' '/rw=/{split($2,li,",");print li[1];}' hdd_sdd_randread.log | xargs
# 对 Fio 文件中测试 iodepth 的提取
awk -F'iodepth=' '/rw=/{split($2,li,",");print li[1];}' hdd_sdd_randread.log
awk -F'iodepth=' '/rw=/{printf("%s ",$2)}' hdd_sdd_randread.log | xargs
# 对 Fio 文件中测试 线程数的 提取
awk -F'jobs=' '/jobs=/{split($2, li, ")");printf("%s ",li[1])}' hdd_sdd_randread.log | xargs
# 对 Fio 文件中测试块大小的提取, 默认单位为 KiB
awk -F'bs=' '/rw=/{split($2,li,"-");split(li[1],li02," ");if(li02[2] ~ "KiB"){gsub("KiB","",li02[2]);printf("%s ",int(li02[2]));}else{gsub("B","",li02[2]);bs=li02[2]/=1024;printf("%s ",bs);}}' hdd_sdd_randread.log | xargs
# 获取 Bios 版本
dmidecode -t bios | grep 'Version:' | sed '1p' -n | awk '{print $2}' | xargs
# 获取 CPU 型号
lscpu | awk '/^Model name:/{i=3;while (i<=NF) {print $i; i++} }' | xargs
# 获取 CPU 数量
lscpu | awk '/^Socket/{print $2}' | xargs
# 获取 盘的 FW
smartctl -i /dev/sda | awk '/^Firmware Version/{print $NF}' | xargs
# 获取 盘 的 序列号
smartctl -i /dev/sda | awk '/^Serial Number/{i=3;while (i<=NF) {print $i; i++}}' | xargs
# 第二种方法
lsblk -d -o 'SERIAL' /dev/sda | sed '$p' -n | xargs
# 获取 盘 的 转动率
smartctl -i /dev/sda | awk '/^Rotation Rate/{i=3;while (i<=NF) {print $i; i++}}' | xargs
# 获取 盘 的用户容量
smartctl -i /dev/sdb | awk '/^User Capacity|^Total NVM Capacity/{i=$(NF-1)$NF;gsub("\\[|\\]","",i);print i}' | xargs
# 获取 盘 的 Model 号
smartctl -i /dev/sda | awk '/^Device Model|^Device Model/{i=3;while (i<=NF) {print $i; i++}}' | xargs
# 第二种方法
lsblk -d -o 'MODEL' /dev/sda | sed '$p' -n | xargs
# 获取 盘 的 厂商名称 Vendor
smartctl -i /dev/sda | awk '/^Device Model|^Model Number|^Vendor/{if($0 ~ /Model/){print $3}else{print $2;}}' | xargs
# 获取盘 的 I/O 调度算法
cat /sys/block/sda/queue/scheduler | sed -e 's#.*\(\[.*\]\).*#\1#g' -e 's/^.//g' -e 's/.$//g'
# 第二种方法
lsblk -d -o 'SCHED' /dev/sda | sed '$p' -n | xargs
# 获取 NVME 盘信息
lspci | grep -i non-v | awk '{print $1}' | xargs -i lspci -vvv -s {} > nvme_AIC_lspci_info.log
# 获取 阵列卡数量
storcli64 show | sed '/Ctl Model/,/Ctl=Controller/p' -n | sed -e '1,2d' -e '$d' -e '/^$/d' | sed '$d'
# 获取 阵列卡 控制 ID
storcli64 show | sed '/Ctl Model/,/Ctl=Controller/p' -n | sed -e '1,2d' -e '$d' -e '/^$/d' | sed '$d' | head -1 | awk '{print $1}'
# 根据 阵列卡控制 ID 获取 机架 ID
storcli64 /c0 show | sed '/EID:Slt/,$p' -n | sed '3p' -n | awk -F':' '{print $1}'
# 获取阵列卡下的所有盘
storcli64 /c0/e251/sall show | sed '/EID:Slt/,$p' -n | sed '/^-.*-$/,/^-.*-$/p' -n | sed -e '1d' -e '$d'
lspci | egrep -i 'raid.*broadcom|contro.*broadcom|contro.*storage'
# PMC
smartpqi
aacraid
# LSI
mpt3sas
megaraid_sas
# PMC 卡语句
# 获取卡列表
arcconf list | sed '/Controller ID/,$p' -n | sed -e '/^$/d' -e '1,2d' -e '$d' | grep 'Controller'
# 获取卡 ID
arcconf list | sed '/Controller ID/,$p' -n | sed -e '/^$/d' -e '1,2d' -e '$d' | grep 'Controller' | awk '{print $2}' | cut -d':' -f1 | xargs
# 根据 nvme 盘符名获取 BUS 号
readlink -f /sys/block/nvme0n1 |cut -d '/' -f 6
# 做性能分析或调优,测试过程中需要收集 iostat 信息
iostat -xdm 1 3 > shi
# linux shell readlink 获取当前脚本文件绝对路径
https://blog.csdn.net/whatday/article/details/105184908
# 解决硬盘乱序的问题
lsscsi -i | awk '{ii=1;while(ii<=NF){if(ii==(NF-1)){ii++;continue;};printf("%-20s",$ii); ii++; };print ""}'
lsblk -d -o 'HCTL,MODEL,SERIAL,SIZE,TYPE,VENDOR,MIN-IO'
lsblk -d -o 'HCTL,MODEL,SERIAL,SIZE,TYPE,VENDOR,MIN-IO,STATE'
lsblk -d -o 'HCTL,MODEL,SERIAL,SIZE,TYPE,VENDOR,MIN-IO,STATE' | sed -e '1d;/disk/p' -n | sort -t ':' -k 3 -n
lsscsi -i | awk '{ii=1;while(ii<=NF){if($ii ~ "^/dev/"){ii++;continue;};printf("%-20s",$ii); ii++; };print ""}'
# 取消 NVME
lsscsi -i -N | awk '{ii=1;while(ii<=NF){if($ii ~ "^/dev/"){ii++;continue;};printf("%-20s",$ii); ii++; };print ""}'
cat dmesg_after | egrep 'scsi.*Direct-Access*'
# 检索 dmesg 日志中的 scsi 设备
cat err_env_2023.06.07.20.44.46/dmesg_after | egrep 'scsi.*Direct-Access*' | awk '{ii=6;while(ii<=NF){printf("%-s",$ii);ii++;}print ""}' > ff4
# 排除 硬盘信息, 排序并格式化
lsblk -d -l -n -o 'HCTL,MODEL,SERIAL,SIZE,TYPE,VENDOR,MIN-IO,STATE' | sed -e 's/INTEL //g' -e 's/^[0-9]*://gp' -n | sort -t ':' -k 2 -n | awk '{ii=1;while(ii<=NF){if(ii ~ /2|3/){printf("%-25s",$ii)}else{printf("%-12s",$ii);};ii++};print " "}'
lsblk -d -l -n -o 'HCTL,MODEL,SERIAL,SIZE,TYPE,VENDOR,MIN-IO,STATE' | sed -e 's/INTEL //g' -e 's/^[0-9]*://gp' -n | sort -t ':' -k 2 -n | xargs -n 8
# 获取各个逻辑盘所对应的 V ID
storcli64 /c0/vall show | sed '/^DG\/VD/,/^VD=Virtual/p' -n | sed -e '/^$/d' -e '/Optl/p' -n | awk '{print $1}' | cut -d'/' -f2 | xargs
# 网卡
lspci -vvv -s 18:00.0 2> /dev/zero | egrep -i '[[:space:]]LnkCap:|[[:space:]]LnkSta:' | awk -F: '{print $2}' | sed 's/\t//gp' -n | awk -F',' '{ii=1;while(ii<=NF){if($ii ~ "Speed|Width")printf("%-16s",$ii);ii++}print " ";}'
lspci -vvv -s 18:00.0 2> /dev/zero | egrep -i '[[:space:]]LnkCap:|[[:space:]]LnkSta:' | awk -F: '{print $2}' | sed 's/[[:space:]]*//gp' -n | awk -F',' '{ii=1;while(ii<=NF){if($ii ~ "Speed|Width")printf("%-16s",$ii);ii++}print " ";}'
lshw -C network | awk 'BEGIN{RS="*-network[:0-9]*"; FS="\n"}{if ($0 ~ "logical name.*ens2np0\n"){printf $0"\n";}}'
cat lshw_info | awk 'BEGIN{RS="*-network[:0-9]*"; FS="\n"}{if ($0 ~ "logical name.*ens2np0\n"){printf $0"\n";}}' | egrep 'description|product|vendor|bus info|logical name|serial|width|capacity' | sed 's#^\s*##gp' -n
cat lshw_info | awk 'BEGIN{RS="*-network[:0-9]*"; FS="\n"}{if ($0 ~ "logical name.*ens2np0\n"){printf $0"\n";}}' | awk -F':' '/configuration/{print $2}' | awk '{ii=1;while(ii<=NF){print $ii;ii++}}' | egrep 'autone|driver|version|duplex|firm|link|port|multi'
cat lshw_info | awk -v ddd="ens2np0" 'BEGIN{RS="*-network[:0-9]*"; FS="\n"}{if ($0 ~ "logical name.*"ddd"\n"){printf $0"\n";}}' | awk -F':' '/configuration/{print $2}' | awk '{ii=1;while(ii<=NF){print $ii;ii++}}' | egrep 'autone|driver|version|duplex|firm|link|port|multi'
SCSI 子系统讲解
lsscsi
-s 显示容量大小。
-c 用全称显示默认的信息。
-d 显示设备主,次设备号。
-g 显示对应的sg设备名。
-H 显示主机控制器列表,-Hl,-Hlv。
-l 显示相关属性,-ll,-lll=-L。
-v 显示设备属性所在目录。
-x 以16进制显示lun号。
-p 输出DIF,DIX 保护类型。
-P 输出有效的保护模式信息。
-i 显示udev相关的属性-w 显示WWN
-t 显示相应传输信息(ATA,FC,SBP,ISCSI,SPI,SAS,SATA,USB),-Ht,-tl.(包括sas地址)<br><br>
列出SCSI设备(或主机)及它们的属性
第一列:SCSI设备id:host, channel,id,lun。
第二列:设备类型。
第3,4,5列:设备厂商,型号,版本信息。
最后一列:设备主节点名
从编号可以看出,第一级是host,第二级是channel,第三级是target编号,第四级是LUN号
h == hostadapter id (first one being 0)
c == SCSI channel on hostadapter (first one being 0)
t == ID
l == LUN (first one being 0)
一个主板可能接多个host,比如上面的服务器,在有多个sas芯片的情况下,肯定就有多个host。一个sas芯片又可以分割为多个通道,也就是channel,也叫bus。一个通道下多个target,一个target下多个lun。
如果一个硬盘支持双通道,那么在scsi层,就是展示为两个scsi标号。
注意channel编号和id编号是底层驱动自行管理的,而host编号(也就是前k)则是linux scsi子系统自行管理(参看static DEFINE_IDA(host_index_ida)(drivers/scsi/host.c))
引入target概念后,每个device内部可以看成被分为被多个target,每个target下面接着多个lun
lun是能够接收scsi命令的主体
# 执行以下命令扫描总SCSI线
echo "- - -" > /sys/class/scsi_host/host5/scan
hostX中"X"是是主机的序号, 如果/sys/class/scsi_host目录下有多个的话, 需要对每一目录都执行该操作
“- - -” 是通配符, 告诉SCSI总线需扫描所有的控制器、通道和;UN
# 重新扫描特定设备
echo “1” > /sys/class/block/sdX/device/rescan
sdX "X"是需要重新扫描的设备
“1” 是标志使SCSI重新扫描该设备,更新该设备的信息
# 移除现有的硬盘
echo "scsi remove-single-device 0 0 10 0 " > /proc/scsi/scsi
# 添加现有的 scsi 设备, 若不存在则无法生效
echo "scsi add-single-device 0 0 10 0 " > /proc/scsi/scsi
# scsi_id命令:查询scsi设备id号;
scsi_id –g –u –s /dev/sda
# HBA WWWN:
cat /sys/class/fc_host/host*/node_name
# DISK wwwn:
ls -l /dev/disk/by_id|grep -v part
# 手动删除path:
先offlne
echo offline >/sys/block/device-name/device/state
然后remove
echo 1 >/sys/block/device-name/device/delete
主机识别存储设备标记主要有三个参数:
C — Controller
T — Target
D — Disk
主机识别存储上的设备就是依照这三个CTD的参数来识别的。
换言之, 如果CTD相同,并且磁盘的signature(label in unix/linux)信息也相同,主机就会认为是同一个LUN。
而CTD或是signature有任何一个参数发生变化, 操作系统就会认为是一个新的LUN。
# 概念讲解
SCSI(Small Computer System Interface)小型计算机系统接口
lun的全称是logical unit number,也就是逻辑单元号
HBA的全称为Host Bus Adapter,即主机总线适配器
SATA(Serial Advanced Technology Attachment)即(串行高级技术附件,一种基于行业标准的串行硬件驱动器接口)
SAS(Serial Attached SCSI),串行连接SCSI接口,串行连接小型计算机系统接口
FC(Fibre Channel)光纤通道。是一种跟SCSI 或IDE有很大不同的接
IDE(Integrated Drive Electronics)即“电子集成驱动器”,它的本意是指把“硬盘控制器”与“盘体”集成在一起的硬盘驱动器
SCSI 参考网址
https://blog.51cto.com/u_15080020/4221032
https://zhuanlan.zhihu.com/p/560321850
https://www.cnblogs.com/timlong/p/6096173.html
https://www.cnblogs.com/timlong/p/6096202.html
磁盘监控工具 --- iostat
# iostat [ -c | -d ] [ -k ] [ -t ] [ -V ] [ -x [ device ] ] [ interval [ count ] ]
其中,-c为汇报CPU的使用情况;-d为汇报磁盘的使用情况;-k表示每秒按kilobytes字节显示数据;-t为打印汇报的时间;-v表示打印出版本信息和用法;-x device指定要统计的设备名称,默认为所有的设备;interval指每次统计间隔的时间;count指按照这个时间间隔统计的次数。
# iostat 查看磁盘分区情况
[root@localhost small_fio]# iostat -p /dev/sda
Linux 4.19.90-2102.2.0.0062.ctl2.x86_64 (localhost.localdomain) 05/26/2023 _x86_64_ (64 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.38 0.00 1.37 0.00 0.00 98.25
Device tps kB_read/s kB_wrtn/s kB_dscd/s kB_read kB_wrtn kB_dscd
sda 0.46 3.76 2.55 0.00 275859 187497 0
sda1 0.01 0.09 0.00 0.00 6416 1 0
sda2 0.01 0.44 0.00 0.00 32653 32 0
sda3 0.45 3.19 2.55 0.00 234002 187464 0
硬盘SATA 1.0 的实际读写速率是150MB/s,带宽1.5Gb/s。
硬盘SATA 2.0的实际读写速率是300MB/s,带宽3Gb/s。
硬盘SATA 3.0的实际读写速率是600MB/s,带宽6Gb/s。
iostat 命令详解
性能调优
NVME
for i in {0..11};do nvme set-feature /dev/nvme${i}n1 -feature-id 0x08 -value 0x0109;done
echo 0 > /proc/sys/kernel/perf_cpu_time_max_percent
echo 10000 > /proc/sys/kernel/perf_event_max_sample_rate
FIO 调优网页参考
FIO 磁盘性能测试
FIO 配置文件压测
NUMA 配置详解
HDD -- 固件更新
通用方法 ---- hdparm
# 通用方法, Solidigm HDD
os_disk_symbol=$(echo $(lsblk |grep -B1 -E "part|boot" |grep -E "^sd[a-z]+|^nvme" |awk '{print $1}') |sed 's/ /|/')
hdds=`lsblk | grep disk | awk '{print $1}' | grep -v ${os_disk_symbol}`
fw_file="skybolt_512E_back_compatible_CCA8.txt"
for dddd in ${hdds}
do
echo "Starting FW Install Of: /dev/${dddd}"
hdparm --fwdownload ./7CV10111_7B1B0011_signed.bin --yes-i-know-what-i-am-doing --please-destroy-my-drive /dev/${dddd}
done
其他厂商工具
# 西部数据固件升级---- Z:\Project\IT_RACK\Option\发布区\硬盘类工具
fw_file="V8GAW9G0.bin"
for dddd in `hugo s | awk '/Ready/{print $4}'`
do
echo "Starting FW Install Of: Serial: ${dddd}"
hugo update -f ${fw_file} -s ${dddd}
if [ $? -eq 0 ]; then
echo "Device fw install is Successful : ${dddd} --- ${fw_file}"
else
echo "Device fw install is Failed : ${dddd} --- ${fw_file}"
fi
done
# SEAGATE SAS HDD 盘固件升级方法
fw_file="skybolt_512E_back_compatible_CCA8.txt"
for dddd in `lsblk | grep '1.7T' | awk '{print $1}'`
do
echo "Starting FW Install Of: /dev/${dddd}"
SeaChest_Lite_101_1183_64 --downloadFW ./${fw_file} -d ${dddd}
done
# 忆联盘固件升级如下:
for dddd in ${nvmes}
do
echo "Starting FW Install Of: Serial: ${dddd}"
yes | umtool updatefw -d ${dddd} -f ${fw_file} -s 1 -a 1
if [ $? -eq 0 ]; then
echo "Device fw install is Successful : /dev/${dddd} --- ${fw_file}"
else
echo "Device fw install is Failed : /dev/${dddd} --- ${fw_file}"
fi
done
NVME 工具详解 - - nvme
ledctl locate=/dev/rsnvmeX
# 查看序列号
nvme id-ctrl /dev/nvmeX | grep -i sn
# 使设备脱机
sh -c"echo 0 >/sys/block/nvmeX/device/delete"
# 查看设备列表信息
nvme list
# 查看 smart 属性信息
nvme smart-log <device>
# 查看 Error log 信息
nvme error-log <device>
# 获取 日志 log 信息
nvme get-log <device>
# 获取 fw-log 日志
nvme fw-log <device>
# 查看设备控制器信息
nvme id-ctrl <device>
# 设备控制器复位
nvme reset <device>
# NVME 设备整盘格式化, 安全擦除
nvme format <device> -s 0/1 # 其中 -s 0 表示高格, -s 1 表示低格
nvme format <device> -n 1 -s 0/1 # 指定 ns 格式化
# 温度阈值
[root@localhost tmp02]# nvme get-feature /dev/nvme0n1 -feature-id 0x04
get-feature:0x4 (Temperature Threshold), Current value:0x00015f
# 队列数量
[root@localhost tmp02]# nvme get-feature /dev/nvme0n1 -feature-id 0x07
get-feature:0x7 (Number of Queues), Current value:0x7f007f
# 中断合并
[root@localhost tmp02]# nvme get-feature /dev/nvme0n1 -feature-id 0x08
get-feature:0x8 (Interrupt Coalescing), Current value:00000000
# 异步事件配置
[root@localhost tmp02]# nvme get-feature /dev/nvme0n1 -feature-id 0x0b
get-feature:0xb (Async Event Configuration), Current value:0x000100
SSD --- 稳态配置
# 稳态顺序写
fio --readwrite=write --bs=128k --iodepth=128 --numloop=2 -end_fsync=0 -group_reporting -direct=1 -ioengine=libaio -thread -buffer_compress_percentage=0 -invalidate=1 -np -randrepeat=0 -exitall --name=nvme2n1_write_fragment1 --filename=/dev/nvme2n1
# 稳态随机写
fio --readwrite=randwrite --bs=4k --iodepth=128 --numjobs=4 --loop=2 -end_fsync=0 -group_reporting -direct=1 -ioengine=libaio -thread -buffer_compress_percentage=0 -invalidate=1 -norandommap -randrepeat=0 -exitall --filename=/dev/nvme3n1 --name=nvme3n1_randwrite_fragment2
Smartctl ------ 工具详解
"/dev/hd[a-t]" # IDE/ATA 磁盘
"/dev/sd[a-z]" # SCSI devices磁盘。注意,对于SATA磁盘,由于是通过libata
选项及含义
选项 |
含义 |
-i |
打印基本信息 |
-a |
打印磁盘所有的SMART信息 |
-A |
显示磁盘支持的厂商指定SMART特性 |
-x |
|
-t |
自检 |
-s |
smartctl 功能开关 |
-H |
显示磁盘是否健康 |
--scan |
|
-d |
指定盘的类型 |
参考命令
# 打印自测和属性错误
smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda
# 启用SMART
smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda
# 打印基本信息(磁盘设备号、序列号、固件版本…)
smartctl -i /dev/sda
# 打印磁盘所有的SMART信息
smartctl -a /dev/sda
# 显示磁盘支持的厂商指定SMART特性。这些特性的编号从1-253,并且有指定的名字
smartctl -A /dev/sda
# 显示磁盘是否健康
smartctl -H /dev/nvme0n1
# 显示硬盘错误汇总
smartctl -l error /dev/nvme0n1
# 可设置的磁盘类型为:
error 只显示error log。
selftest 只显示selftest log
selective 只显示selective self-test log
directory 只显示Log Directory
background
scttemp
# smartctl -t short # 后台检测硬盘,消耗时间短;
# smartctl -t long # 后台检测硬盘,消耗时间长;
# smartctl -C -t short # 前台检测硬盘,消耗时间短;
# smartctl -C -t long # 前台检测硬盘,消耗时间长。
# smartctl -X # 中断后台检测硬盘。
# 扫描所有磁盘
smartctl --scan
# 只扫描所有 NVME 盘
smartctl --scan -d nvme
# 可使用的类型如下:
ata, scsi[+TYPE], nvme[,NSID], sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbprolific, usbsunplus, sntjmicron[,NSID], intelliprop,N[+TYPE], jmb39x,N[,sLBA][,force][+TYPE], marvell, areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N, aacraid,H,L,ID, cciss,N, auto, test
网页参考
smartctl 输出详解
smartctl 命令解释
显示磁盘和分区信息 --- lsblk
选项及含义
选项 |
含义 |
-d |
只显示设备,不显示分区等 |
-p |
显示完整路径 |
-l |
以列表形式显示 |
-o |
以指定格式输出设备和分区信息 |
-n |
不打印表格标题 |
-x |
指定表格中指定列进行排序 |
-t |
以树形结构显示信息 |
-f |
显示文件系统类型 |
-e |
按照主要设备编号,排除指定类型设备,默认为 ram disk |
-s |
反向依赖输出,把树形结构倒过来 |
-S |
只打印有关 scsi 设备的信息 |
-r |
使用原始输出格式,非表格格式 |
-p |
打印有关权限的信息 |
-I(大写的 i) |
仅显示具有主要编号的设备 |
|
|
# 显示分区及逻辑卷的挂载点信息
lsblk -pf
for f in `lsblk -n -d -o 'NAME,MODEL,SERIAL' | grep MZ7L3480 | awk '{print $1}'`; do printf "${f}";printf " `smartctl -a /dev/$f|grep Fir|cut -d':' -f2 | xargs`\n"; done
lsblk -o 'NAME,MODEL' | grep -i samsung | awk '{print $1}' | xargs -i smartctl -a /dev/{} | grep -i firmware
lsblk -d -o 'NAME,MODEL,SERIAL,SIZE'
lsblk -l -d -o 'NAME,MODEL,SERIAL,SIZE,HCTL,UUID,STATE,ROTA,SCHED,RQ-SIZE,WWN,VENDOR,REV' -x HCTL
NAME # 设备名
MODEL # model 号, 截取固定长度
SERIAL # 序列号
SIZE # 大小
HCTL # SCSI ID
UUID # 分区 UUID
STATE # 状态
ROTA # 是否是HDD, 若是 SSD 则该值为 0 , HDD 为 1
SCHED # 磁盘调度算法
RQ-SIZE #
WWN
VENDOR # 厂商
REV # 固件 , 截图固定长度字符
MAJ:MIN # 是内核内部用来识别设备的编号,第一个数字表示类型为主要编号【不同的类型内核以规定好】, 第二个数字为次要编号,比如8表示scsi设备, 259 代表 NVME 设备,253 代表逻辑卷设备, 11 代表 rom 设备;
MOUNTPOINT # 挂载点
FSTYPE # 文件系统类型
# 增加表格列信息
lsblk -d -o +rota
# 显式指定查看某一设备的信息
lsblk /dev/sda
# 只显示指定编号的设备
lsblk -I 8
# 只输出所有 NVME 盘的盘符
lsblk -o TRAN,NAME -d -n | awk '/^nvme /{print $2}' | xargs
# 等价于
lsblk -I 259 -d -n -o NAME
# 排除 rom 设备和 NVME 设备,显示其他类型设备信息
lsblk -e 11 -e 259 -d -n
# 只输出所有 HDD 盘的盘符
lsblk -o ROTA,NAME -d -n | awk '{if($1 == "1"){print $2}}' | xargs
# 只打印输出 SCSI 设备盘符,包含 SCSI 逻辑设备
lsblk -d -I 8 -o NAME -n | xargs
# 只打印输出 rom 设备, 例如通过 KVM 挂载的设备
lsblk -I 11
# 只打印所有逻辑卷的卷路径
lsblk -s -I 253 -p -d -n -o NAME
# 输出设备的权限,属主属组信息
lsblk -m
# 查看主分区所在的设备路径
lsblk -P -p -o NAME,MOUNTPOINT | awk '/MOUNTPOINT="\/"$/{print $0}' | cut -d'"' -f2
# 查看根分区和 boot 分区所在的内核主编号和次要编号
lsblk -n -l -o MOUNTPOINTS,MAJ:MIN | awk '/^\/|\/boot/{print $2}' | xargs
Linux命令之lsblk命令
关于major、minor的解释
其他
sftp指定端口连接:
sftp -oPort=10022 HA@10.1.2.3:/HA
ftp方式连接:
ftp 10.1.2.3 21
zip带密码解压缩到指定目录:
unzip -P passwd123 -o aaa.zip -d /data/
linux 乱码后解码:
echo -e '\xf'
查看占用端口:
netstat -anp |grep 9200
查看主机硬件时间:
hwclock -r
查看cpu核数:
nproc (或 cat /proc/cpuinfo|grep processor|wc -l)
# 测试内存与缓存延迟的工具
https://blog.csdn.net/qq_53169429/article/details/121296269
HGST(日立) 被 西数 收购了
Solidgm 被 SK Hynix(海力士) 收购了
自动化脚本
性能测试脚本
Fio 数据自动解析脚本
Question &&& Solution
通过 DD 打 阵列卡驱动
8.3 OS安装过程中驱动更新方法
(1) 上述更新方法为常规OS下,如果在安装过程中无法识别阵列卡,需要先安装驱动,请按以下操作进行。
(2) 当前驱动文件夹中提供对应OS的dd.iso,将其挂载在KVM中。
(3) 开始OS引导,以RHEL7.6为例,进入选择菜单时,按e进入grub。
(4) 在linuxefi …行最后添加“linux dd”,按ctrl + x开始引导。
(5) 进入后会先选择驱动所在路径,选择挂载介质菜单选项,按空格选择,按c继续,根据提示继续操作,进入后即可安装OS。
或者用这个方法用dd包更新我放在100盘里的驱动试试