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盘里的驱动试试