硬盘性能测试笔记学习全套 -- Fio

Top

I/O 读写工具 --- FIO

FIO 下载地址

Github Download -- FIO

cgit/refs Download -- Fio

Kernel Download -- FIO

FIO 安装

./configure --enable-gfio # 只有加这个参数才能编译安装gfio
make fio
make gfio
make install

参数解析

# 常见的自定义选项分类如下:
文件系统类型:在测试文件系统性能时,可以选择不同的文件系统类型,如 ext4、xfs、btrfs 等。
文件大小:可以指定测试文件的大小,以便模拟不同大小文件的性能。
读写比例:可以调整读写比例,以模拟不同的工作负载。
数据块大小:可以指定数据块的大小,以便模拟不同大小的数据块操作。
操作类型:可以指定操作类型,如顺序读写、随机读写、混合读写等。
连续读写:可以指定连续读写操作的大小,以模拟不同的连续读写性能。
读写缓存:可以指定读写缓存的大小,以便调整读写缓存的影响。
并行度:可以指定并行度,以模拟不同的并发读写操作。
运行时间:可以指定测试运行时间,以评估长时间运行时的性能表现。
周期时间:可以指定周期时间,以便在测试过程中进行周期性操作。
预置操作:可以指定预置操作,以便在测试前进行预热操作。
延迟时间:可以指定延迟时间,以便在测试过程中引入延迟。
作业数:可以指定作业数,以模拟不同的作业数影响。
模式:可以指定模式,如同步模式、异步模式等。
持久化:可以指定持久化选项,以便将测试结果保存到文件中。

# 
--bs=4k            # 表示 I/O block大小,默认是4k; 也可指定为 --blocksize=4k
--numjobs=16       # 指定job的克隆数(线程)
--iodepth=64 ${PARA_LINE}  # 表示 I/O 队列深度; 如果ioengine采用异步方式,该参数表示一批提交保持的io单元数
--runtime=300s     # 指定在多少秒后停止进程。如果未指定该参数,fio将执行至指定的文件读写完全完成
--filename=/dev/${DEV_LIST}  # 表示要测试的裸设备(硬盘或分区); 切勿在系统分区做测试,会破坏系统分区,而导致系统崩溃。若一定要测试系统分区较为安全的方法是:在根目录下创建一个空目录,在测试命令中使用directory参数指定该目录,而不使用filename参数
--name=${DEV_LIST}_${RW}_4k_16_64  # 定义测试任务名称。
--directory  # 

--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测试; 该参数在编写高质量Fio脚本时很重要, 若添加该参数,则当前 Fio 只有一个主进程,或有多个 numjobs 个子线程,使用pgrep 和 pidstat 命令查询进程只能查到一个主进程,推荐这种方式,因为这种方式较为节约资源; 然而若不添加该参数,则当前 Fio 会有一个主进程,或有多个 numjobs 子进程,使用pgrep 和 pidstat 命令查询进程时则可以查询到 numjobs + 1 个进程;这一点在写脚本时一定要注意;
--time_based  # file若已被完全读写或写完,强制执行完runtime规定的时间。它是通过循环执行相同的负载来实现的,与runtime相对应
--group_reporting  # 定义测试结果显示模式,group_reporting 表示汇总每个进程的统计信息,而非以不同 job汇总展示信息

-buffer_compress_percentage=0  # 设定缓冲区数据的压缩级别
-invalidate=1
--end_fsync=0 
--norandommap=<0/1> # 表示是否使用预定义的文件映射,使用预定义的文件映射可能会导致测试结果不准确,因为预定义的文件映射可能无法完全模拟实际文件系统的使用情况。因此,在实际生产环境中,建议使用随机映射进行测试; fio在做随机IO时,将会覆盖文件的每一个block.设置–norandommap=1的话,fio将只是获取一个新的随机offset,而不会查询过去的历史。这意味着一些块可能没有读或写,一些块可能要读/写很多次;
--randrepeat=<0/1>  # 对于随机IO负载,配置生成器的种子,使得路径是可以预估的,使得每次重复执行生成的序列是一样的, 不设置为 0 的话, 但会影响seqwrite,randwrite,randread,
-exitall 
--size=${FILE_SIZE}  # 定义测试IO操作的数据量,若未指定runtime这类参数,fio会将指定大小的数据量全部 读/写完成,然后才停止测试。该参数的值,可以是带单位的数字,比如size=10G,表示读/写的数据量为10GB;也可是百分数,比如size=20%,表示读/写的数据量占该设备总文件的20%的空间。建议测试数据量为内存两倍大,尽量避免缓存影响
--offset_increment=100G # 表示跳过指定的数据量大小,

--loop   # 定义硬盘执行的圈数, loops与runtime是两个不能同时存在的两个参数
--ramp_time # 设定在记录任何性能信息之前要运行特定负载的时间。这个用来等性能稳定后,再记录日志结果,因此可以减少生成稳定的结果需要的运行时间
--startdelay=int   # fio启动几秒后再启动job。只有在job文件包含几个jobs时才有效,是为了将某个job延时几秒后执行,可以让多个job之间有一定的时间间隔。
与ramp_time的区别就是startdelay是job任务完全不运行,就是闲等,ramp_time是指job开始执行你指定的任务了,但是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   # 每个进程生成文件的数量

-uid='int'  # 用户 ID 
-gid='int'  # 组 ID 
--rate_iops=500  # 锁定IOPS
--rate=100m      # 锁定带宽
# 用来设置采样点的参数。它接受一个由百分比组成的列表,表示在测试过程中需要采集哪些百分比的响应时间数据
percentile_list=1:5:10:25:50:75:90:95:99:99.5:99.9:99.99:99.999:99.9999:99.99999:99.999999

--verify=0  # 如果写入文件,是否校验文件内容


################################  测试报告
--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  会高些

# 其他
--description=str  # 配置输出标识
--bssplit  # 设备读写访问的IO大小分配比例,例:-bssplit=4k/30:8k/40:16k/30,随机读4k文件占30%、8k占40%、16k占30%
--bsrange   # 设置IO的块文件大小的范围,例如-bsrange=512-2048
--lockmem   # 对测试所使用的内存进行限制,如-lockmem=1g,限制1G
--zero_buffers  # 用0初始化系统buffer
--nrfiles=int     # 每个进程生成文件的数量
--filesize=int  # 单个文件的大小,可以是一个范围,在这种情况下,fio将会在一个范围内选择一个大小来决定单个文件大小,如果没有设置的话,所有的文件将会是同样的大小。
使用nrfiles和filesize这两个参数,可以使每个job(每个任务的每个线程或进程)生成指定数量特定大小的文件,这样对于后端是分布式的文件系统,模拟会更真实。(如果是通过size=int和filename=str两个参数,生成的会只有一个名为str,大小为size的文件)
注意此参数与bs参数的区别,bs是控制一次访问的块的大小的,而filesize是控制被访问的文件的大小的,例如bs=4K, fileszie=1M,fio则会以每次4K的请求大小来访问1M的文件

--create_only=bool  # 如果设置为true的话,fio将只会生成测试需要的文件但是不执行任务,可以用它来创建大量的文件(配合nrfiles和filesize)
--unlink=bool  # job运行完毕后会删除运行过程中产生的测试文件。但可能会使测试文件被反复创建,浪费测试时间。


--showcmd=jobfile   # 将job文件的内容转换为命令行参数
--stonewall,wait_for_previous  # 在一个有多个job的文件中,可以多个job逐个执行(stonewall后面将是一个新的group),通常用于需要执行多种不同的任务时,让任务按顺序执行
这两个参数其实功能基本相同,只是使用的位置有所不同,stonewall一般放在一个job任务的末尾,wait_for_previous一般放在一个job任务的开头

--openfiles=int   # 在同一时间可以同时打开的文件数目,默认同nrfiles相等,可以设置小一些,来限制同时打开的文件数目。可以通过设置它模拟指定的负载;
--exec_postrun=str # 运行job之前,通过过system执行指定的命令; exec_preren与exec_postrun可以再job运行前后执行一些命令,配合你的测试

--readonly  # 启用只读安全检查
--max-jobs  # 设置最大支持的作业数
--bandwidth-log  # 生成每个作业的带宽日志
--client       # 设置要完成作业的主机信息
--daemonize    # 指定要将PID信息写入到的文件
--latency-log  # 生成每个作业的延迟日志
--debug        # 使用调试模式
--eta          # 设置何时输出ETA评估值

测试模式配置

--readwrite=${RW}   # 表示测试类型, 选项可简写为 --rw ;  可选模式如下:
		1. 顺序读  -rw=read 
		2. 随机读  -rw=randread,
		3. 顺序写  -rw=write
		4. 随机写 -rw=randwrite
		5. 混合随机读写模式  -rw=randrw
		6. 顺序随机读写模式 --rw=rw  # 默认的比例是50/50

常用测试模型 6 要素配置

--bs=4k           # 块大小
--numjobs=2       # 线程数
--iodepth=32       # I/O对队列深度
-direct=1           # 禁用 系统缓存 
-ioengine=libaio    #  I/O 请求模型引擎: psync, rdma ,spdk 
-thread             # 使用线程的方式

绑核和内存相关配置

--cpumask=int   # 设置此作业的CPU亲和性。给定的参数是作业可以运行的允许CPU的位掩码;建议直接使用 --cpus_allowed 参数即可;
--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'
--numa_mem_policy=str  # 设置此作业的内存策略和相应的NUMA节点; 默认,prefer; 可选的内存策略为:prefer,bind,interleave或local

测试日志输出配置

--log_avg_msec=1000  # 设置写入磁盘日志的间隔时间,单位为毫秒
--iopsavgtime=1000   # 平均计算IOPS的时间。单位为毫秒; 如果作业还通过 write_iops_log进行IOPS记录,则将使用此选项和 log_avg_msec 的最小值, 默认值:500ms;
--bwavgtime=1000     # 平均计算带宽的时间。单位为毫秒; 如果作业还通过 write_bw_log  进行 BW 记录,则将使用此选项和 log_avg_msec 的最小值。 默认值:500ms;
--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 , 针对每个 线程都会生成一个文件
--minimal            # 使用简洁格式显示统计信息,但不易人类阅读,不建议使用

测试执行时间相关配置

--runtime=300s     # 指定在多少秒后停止进程。如果未指定该参数,fio将执行至指定的文件读写完全完成
--time_based       # file若已被完全读写或写完,强制执行完runtime规定的时间。它是通过循环执行相同的负载来实现的,与runtime相对应

--ramp_time # 设定在记录任何性能信息之前要运行特定负载的时间。这个用来等性能稳定后,再记录日志结果,因此可以减少生成稳定的结果需要的运行时间
--startdelay=int   # fio启动几秒后再启动job。只有在job文件包含几个jobs时才有效,是为了将某个job延时几秒后执行,可以让多个job之间有一定的时间间隔。
             与ramp_time的区别就是startdelay是job任务完全不运行,就是闲等,ramp_time是指job开始执行你指定的任务了,但是ramp_time时间内不会做记录

--loops=2    # 定义硬盘执行的圈数, loops与runtime是两个不能同时存在的两个参数
--size=${FILE_SIZE}  # 定义测试IO操作的数据量,若未指定runtime这类参数,fio会将指定大小的数据量全部 读/写完成,然后才停止测试。该参数的值,可以是带单位的数字,比如size=10G,表示读/写的数据量为10GB;也可是百分数,比如size=20%,表示读/写的数据量占该设备总文件的20%的空间。建议测试数据量为内存两倍大,尽量避免缓存影响
--offset_increment=100G # 表示跳过指定的数据量大小,

随机读、随机写 相关配置参数

Fio性能相关参数详解

结果分析

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

单位换算

# 单位解析
KB, MB, GB, TB     这几个单位是 10 进制,进位为 10^3 = 1000
例如:
	KB = 10^3 = 1000
	MB = 10^6 = 1000,000 = 1000 * 1000
	GB = 10^9 = 1000,000,000 = 1000 * 1000 * 1000
	TB = 10^12 = ...... 略
KiB, MiB, GiB, TiB 这几个单位是 2  进制,进位为 2^10 = 1024
例如:
	KiB = 2^10 = 1024
	MiB = 2^20 = 1048,576 = 1024 * 1024 
	GiB = 2^30 = 1073,741,824 = 1024 * 1024 * 1024 
	TiB = 2^40 = ......略
	
Mbit/s的意思是每秒中传输10^6 bit的数据,也写成 Mbps
MB/s的意思是每秒中传输10^6 byte的数据, 也写为 MBps, 等于  8 倍的 Mbps
MiB/s的意思是每秒中传输2^20 byte的数据

# 综上:
PS: 如果一个运营商声称自己的传输带宽是 1MBps, 若换算为 MiBps 的话,则等于 1 / 1.024 / 1.024 ~= 0.9537
PS: 如果一个硬盘厂商声称自己的盘的容量大小为 1TB, 若换算为 GiB 的话,则等于 1 * 1000 / 1.024 / 1.024 / 1.024 ~= 931.3 GiB
GiB = GB / 1.024 / 1.024 / 1.024 ~= GB / 0.9313 
1GB = 0.9313225746 GiB
MB/s = MiB/s * 1.024 * 1.024 ~= MiB/s * 1.048 
MB/s = Mbit/s * 8
Mbit/s = MiB/s * 1.024 * 1.024 * 8 ~= 8.389

# 其他
系统下通过 nvme list 命令查看到盘的大小单位是: TB, GB,
而通过 lsblk 命令查看到的盘大小单位是: TiB, GiB

自定制绘图脚本

Fio 结合 SPDK 测试

1. 编译安装 Fio 和 SPDK (注意安装各个依赖包)
2. 执行SPDK 准备好的脚本: scripts/setup.sh , 进行配置 SPDK 环境 
3. 开始执行 Fio 测试 

LD_PRELOAD=/suosuo/spdk-home/spdk/build/fio/spdk_nvme  /suosuo/spdk-home/fio/fio '--filename=trtype=PCIe traddr=0000.03.00.0 ns=1'  --numa_cpu_nodes=0 --output=4K_8_256_randread.log spdk_nvme1.fio

# spdk_nvme1.fio 文件内容如下:
        [global]
        ioengine=spdk
        thread=1
        group_reporting=1
        direct=1
        verify=0
        time_based=1
        ramp_time=0

        [job]
        rw=randread
        bs=4k
        numjobs=8
        iodepth=256
        runtime=300

相关命令

# 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'


Fio 性能测试总结

1、请不要在系统盘或者数据盘上进行FIO测试,避免损坏系统文件或擦除数据
2、FIO测试硬盘性能时,推荐直接测试裸盘(如/dev/sdc);测试文件系统性能时,推荐指定具体文件测试比如(/mnt/data/file)
3、FIO测试时请注意磁盘尽量为空,磁盘在使用大部分容量的情况下,IO性能测试结果明显降低。
4、FIO测试时block = 128k iodepth=32 比较能反映磁盘IOPS性能,但不是很绝对。
5、阵列卡的电容是否存在以及状态是否正常直接影响阵列卡Cache是否能正常使用。
6、FIO测试建议使用官网兼容的系统。
7、FIO测试建议使用官网最新的固件与驱动。
8、FIO测试需要明确逻辑盘的Cache是否打开以及比例是否为10:90。

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 输出信息解析

rrqm/s:每秒这个设备相关的读取请求有多少被Merge了(当系统调用需要读取数据的时候,VFS将请求发到各个FS,如果FS发现不同的读取请求读取的是相同Block的数据,FS会将这个请求合并Merge);
wrqm/s:每秒这个设备相关的写入请求有多少被Merge了。
r/s: 该设备的每秒完成的读请求数(merge合并之后的)
w/s:  该设备的每秒完成的写请求数(merge合并之后的)
rsec/s:每秒读取的扇区数;
wsec/:每秒写入的扇区数。
rKB/s:每秒发送给该设备的总读请求数 
wKB/s:每秒发送给该设备的总写请求数 
avgrq-sz 平均请求扇区的大小
avgqu-sz 是平均请求队列的长度。毫无疑问,队列长度越短越好。    
await:  每一个IO请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
svctm:    表示平均每次设备I/O操作的服务时间(以毫秒为单位)。如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢。
%util: 在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。

iostat 命令详解

磁盘监控工具 --- iotop

    echo 

性能调优

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

SAS/SATA 详解

NVME 工具详解 - - nvme

NVME Docu

ledctl locate=/dev/rsnvmeX
# 查看序列号, 即 SN 号 
nvme id-ctrl /dev/nvme2 | grep -iE '^sn' | awk '{print $NF}'
# 查看 Model 号,即 PN 号
nvme id-ctrl /dev/nvme2 | grep -iE '^mn' | awk '{print $NF}'
# 查看 FW 
nvme id-ctrl /dev/nvme2 | grep -iE '^fr' | awk '{print $NF}'
# 控制器 ID 查询 
nvme id-ctrl /dev/nvme6n1 | grep -E '^cntlid'
# namespace ID 查询; 当该盘与控制器解绑时该方法无法查询
nvme get-ns-id /dev/nvme2n1 | cut -d':' -f3 | xargs
# 列举某个盘所有的 namespace; 即使该盘与控制器解绑也可查询;
nvme list-ns /dev/nvme0   
# 使设备脱机 
sh -c"echo 0 >/sys/block/nvmeX/device/delete"
# 查询一个控制器当前扇区数 LBA,若该盘之前未配置过该盘 OP,则该数值即为该盘最大扇区数 
nvme list --output-format=json  | jq .Devices | jq '.[] | {name: ."DevicePath", lba: ."MaximumLBA"}' | grep "nvme3" -A 1 | grep lba | awk '{print $NF}'
  
# 查看设备列表信息: 可以列出系统中所有的NVMe设备及其相关的信息,包括设备的名称、命名空间的数量、总容量、固件版本等。通过这个命令,管理员可以快速了解系统中所有NVMe设备的情况,并对设备进行进一步的管理和调整
nvme list
# 查看 smart 属性信息: 可以查看指定NVMe设备的SMART信息,包括设备的工作状态、温度、传输错误次数、寿命指标等。通过这个命令,管理员可以监控设备的健康状态,及时发现潜在问题并进行预防维护
nvme smart-log <device>
# 获取 nvme 盘的温度
nvme smart-log /dev/nvme3n1 | grep -E "temperature" | awk '{print $3}'
# 查看 Error log 信息 
nvme error-log <device>
# 获取 日志 log 信息 
nvme get-log <device>
# 获取 fw-log 日志 
nvme fw-log <device>
# 查看设备控制器信息: 可以查看指定NVMe设备的控制器信息,包括厂商信息、序列号、固件版本、支持的命令集等。通过这个命令,管理员可以详细了解设备的控制器信息,为后续的调优和维护工作提供参考依据
nvme id-ctrl /dev/nvme0 
# 查看 namespace 信息: 可以查看指定NVMe设备的命名空间信息,包括命名空间的容量、可用空间、类型、扇区大小等。通过这个命令,管理员可以了解设备的命名空间情况,有助于合理规划存储空间和优化数据布局 
nvme id-ns /dev/nvme0n1
# 设备控制器复位 
nvme reset <device>
# 查看控制器特性信息: 可以查看指定NVMe设备的特性信息,包括是否支持写时拷贝、多项命令和队列等特性。通过这个命令,管理员可以了解设备的特性支持情况,为后续的配置和优化工作提供参考依据
nvme get-feature -f 0x07 /dev/nvme0
# NVME 设备整盘格式化, 安全擦除 
nvme format <device> -s 0/1  # 其中 -s 0 表示高格, -s 1 表示低格
nvme format <device> -n 1 -s 0/1  # 指定 ns 格式化 

# nvme 盘固件升级三步走
nvme fw-download /dev/nvme0n2 -f allBinary.bin
nvme fw-commit /dev/nvme0n2 -s 0 -a 1
nvme reset /dev/nvme0  # 这里使用块设备,  没有后缀  n1 

# 温度阈值
[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

# 查询可用容量
nvme id-ctrl /dev/nvme0n1 |grep tnvmcap

# NVME 盘热插拔 
echo 1 > /sys/bus/pci/devices/${BDF}/remove 

预留空间 -- OP

  OP预留空间,英文名称Over-provisioning,是指固态硬盘内部存在的,由主控芯片控制的,用户不可操作的隐藏空间,这部分空间就是用于主控各种优化机制的操作,比如垃圾回收,磨损平衡、坏块管理等;
  OP预留空间一共分为三层,第一层OP容量是由于单位换算问题产生的,标称容量是千进制的,即1GB=1000Mb,而NAND闪存颗粒是1024进制的,即1GiB=1024kib,其中相差的空间值就是第一层容量,此容量无法更改,也是固定不变的通行于所有品牌,这个差值约为固态硬盘标称容量的7%
  第二层OP容量,则是取决于固态硬盘设计厂商以及主控厂商对于产品的定位了。
  第三层OP容量,是用户可以自行选择自行设置的空间,其作用也同第二层OP空间一致



create-ns 使用提供的参数创建命名空间
delete-ns 从控制器中删除命名空间
attach-ns 将命名空间附加到请求的控制器上
detach-ns 从请求的控制器中删除命名空间

# OP 重置的步骤
  1. 将该盘的 namespace 与 控制器解绑 
    nvme detach -ns /dev/nvmeX(硬盘控制器)-n  <命名空间ID>  -c  <控制器ID>
  2. 删除该盘的 namespace 
    nvme delete-ns /dev/nvme1 –n 1
  3. 设置该盘的 OP , 即重新创建该盘的 namespace 
    nvme create-ns /dev/nvme1 -s 15000000000 -c 15000000000 -f 0 -d 0 -m 0
    # 解释:
      -s  # 指定的扇区数量
      -c  # 指定的扇区数量
      -f  # 是否格式化
      -d  # 数据保护设置
      -m  # 多路径和共享功能
  4. 将该盘的 namespace 与 控制器绑定 
    nvme attach-ns /dev/nvme1 -c 0 -n 1
  5. 激活该盘 
    nvme reset /dev/nvme1

# 忆联盘使用厂商工具设置 OP 
umtool capacity -d nvme6 -s 1000G 

SSD --- 稳态配置(预写)

# 稳态顺序写 
fio --readwrite=write   --bs=128k --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 --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

NVME --- LBA 配置

# 查询该盘支持的 LBA 列表
nvme id-ns /dev/nvme0n1 -n 1 -H | grep LBA
# 设置该盘 LBA 块大小
nvme format /dev/nvme0n1 -n 1 -l  3 -f  # -l 参数用于指定所设置 LBA 格式所对应的序号,具体的可选序号看下图

NVME 盘根据盘符查找 硬盘丝印

NVME 硬盘盘序信息获取流程图

Marvell 卡相关

	Marvell RAID是一款使用M.2 NVMe SSD、支持有限级别且功能有限的存储控制器。也可以把它当成是一个转接卡来看待,只是这张转接卡不像 Retimer卡一样只实现转接的功能
    不支持 Legacy Bios 配置
# Marvell RAID支持的RAID级别:
JBOD
RAID0
RAID1

Marvell 管理工具常用指令

# 查询控制器信息
mnv_cli info -o hba 
# 查询 RAID 信息方法
mnv_cli info –o vd 
# 查询物理盘信息方法
mnv_cli info –o pd
# 命名空间查询
mnv_cli ns --list 
# 冗余 RAID 重建 CLI 指令
mnv_cli rebuild [-a <start|stop>] -i <vd_id> -d <pd_id>
# RAID1 巡检 CLI 指令:
mnv_cli mp [-a <start|stop >] -i <vd_id>

# 组建 RAID 指令
mnv_cli vd –a create –r <raid_level> -d <pd_id> [-b <128|256|512>]。
# 删除 RAID 指令
mnv_cli vd -a delete -i <vd_id>
# 物理盘定位
./mnv_cli led -o rc -i 0/1 -a <on/off/sb/fb>
# 设置log记录功能开关
./mnv_cli log -a on/off
# 收集日志 --- SPI日志, 需提前打开 log 记录开关
./mnv_cli log -a show/show --outputfile=log.txt
# Event日志收集
./mnv_cli event -c 0


# SN和Model写入指令
./mnv_cli oemdata -s "SN" -m "Model Number" 
# SN和Model查询指令
nvme id-ctrl <Device>
# FW 更新 -- 这里需要注意FW提前放置在指定位置:In Linux system:copy file "RawImage\raw.bin" to folder "Update_Tool\linux\bin
./mnv_cli flash -o hba -f raw.bin -c 1 -s 1
# VD导入
./mnv_cli import -l <VD ID>
# 物理盘定位
./mnv_cli led -o rc -i 0/1 -a <on/off/sb/fb>

# Marvell 在 OS 下关于Namespace的管理指令一二(Marvell RAID不支持NS划分):
mnv_cli  attach –i <ns_id> -d <ctrl_id>  # 绑定 ns
mnv_cli  detach –i <ns_id> -d <ctrl_id>  # 解绑ns

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

# lsblk 默认显示所有盘的信息,若要显示指定的盘的信息,可指定多个指定的盘
lsblk /dev/nvme1n1  /dev/nvme2n1  /dev/nvme3n1 /dev/nvme4n1 /dev/sda
# 获取每一个待测盘的第一个分区的完整路径 --- 涉及到排序,
lsblk /dev/nvme1n1  /dev/nvme2n1  /dev/nvme3n1 /dev/nvme4n1 /dev/sda -p -l -n  -x "NAME" | grep part | sed 'N;P' -n | awk '{print $1}' | 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(海力士) 收购了 

U.2 也叫 SFF-8639
U.2 按照接口形态可区分为 B-key, M-key ;
在速率方面 B-key 支持 PCI * 2 ,而 M-key 支持 PCI * 4 
 

参考网址

常用硬盘一览 之《协议、总线、接口》

PCIE2.0/PCIE3.0/PCIE4.0/PCIE5.0接口的带宽、速率计算

存储接口:SATA PCIE USB速率小结

图解 M.2、M.2(NVMe)

SATA、PCIe和M.2——主板上的各种插槽解析

sata协议传输速率(sata的数据传输速率)

相关技术文档

自动化脚本

性能测试脚本



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盘里的驱动试试
posted @ 2023-11-13 02:12  梭梭666  阅读(1790)  评论(0编辑  收藏  举报
返回顶部