文章

磁盘性能测试

磁盘性能测试标准

1
2
3
4
1. 读写顺序: 随机读写、顺序读写
2. 读写块大小: 4k、16k、64k
3. 读写文件大小: **G

磁盘性能测试

1. dd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
常见选项:
bs=<size>:设置块大小。例如,bs=1M 表示每个块 1 MB。指定读写操作的块大小,即每次读写的字节数。这与操作系统文件系统的块大小不同,而是指在 dd 操作过程中使用的传输单位

count=<number>:指定读取的块数。例如,count=10 表示读取 10 个块。

skip=<number>:跳过输入文件开头的块数。例如,skip=5 表示跳过前 5 个块。

seek=<number>:跳过输出文件开头的块数。例如,seek=5 表示在写入数据前跳过前 5 个块。

oflag=<flags>:设置输出文件的标志。例如,oflag=dsync 表示在写入数据后确保数据已同步到磁盘。

iflag=<flags>:设置输入文件的标志。例如,iflag=fullblock 表示确保每个读取块的完整性。



1. 写入性能测试
dd if=/dev/zero of=/path/to/testfile bs=1G count=1 oflag=dsync
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 1.0158 s, 1.1 GB/s

if=/dev/zero:输入文件,/dev/zero 是一个产生零字节的特殊设备文件。
of=/path/to/testfile:输出文件,你可以将 /path/to/testfile 替换为你要测试的实际路径。
bs=1G:块大小为 1GB。你可以根据需要调整块大小(例如 4M 表示 4MB)。
count=1:只写入 1 个块。
oflag=dsync:在写入数据后,确保数据已经同步到磁盘,这样可以更准确地测量性能。


2. 读取性能测试: 会产生多余文件,占用空间,测试后及时删除
dd if=/tmp/testfile of=/dev/null bs=1G
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 2.04944 s, 524 MB/s

if=/tmp/testfile:输入文件,你可以使用之前写入的文件。
of=/dev/null:输出文件,/dev/null 是一个丢弃所有输入的特殊设备文件。
bs=1G:块大小为 1GB。可以根据需要调整块大小。


其他用法
======================
备份整个磁盘: 
将整个磁盘 /dev/sda 备份到一个镜像文件 backup.img:
dd if=/dev/sda of=backup.img bs=4M

恢复磁盘镜像: 
将镜像文件 backup.img 恢复到磁盘 /dev/sda
dd if=backup.img of=/dev/sda bs=4M

创建启动盘:
将 ISO 文件 ubuntu.iso 写入到 U 盘 /dev/sdX(注意替换 /dev/sdX 为实际设备)
dd if=ubuntu.iso of=/dev/sdX bs=4M status=progress

创建文件填充:
创建一个大小为 1 GB 的文件 largefile,并用零填充:
dd if=/dev/zero of=largefile bs=1G count=1


复制文件:
将文件 source_file 复制到 destination_file:
dd if=source_file of=destination_file


测试写入速度:
> dd if=/dev/zero of=testfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.459133 s, 228 MB/s

100+0 records in:输入了 100 个块。
100+0 records out:输出了 100 个块。
104857600 bytes copied:复制了 104,857,600 字节。
228 MB/s:写入速度为 228 MB/s。



2. fio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 安装
yum install fio -y
apt install fio
或者
wget https://brick.kernel.dk/snaps/fio-3.37.tar.gz(最新)
tar -xzvf fio-3.37.tar.gz
cd fio-3.37
make
sudo make install


# 命令参数
filename=/dev/emcpowerb 支持文件系统或者裸设备,-filename=/dev/sda2或-filename=/dev/sdb
direct=1                 测试过程绕过机器自带的buffer,使测试结果更真实
iodepth                  I/O 队列深度,控制并行的 I/O 请求数
ioengine                 I/O 引擎,如 psync 表示同步 I/O
thread                   使用线程模式执行 I/O 操作
rw=randwread             测试随机读的I/O
rw=randwrite             测试随机写的I/O
rw=randrw                测试随机混合写和读的I/O
rw=read                  测试顺序读的I/O
rw=write                 测试顺序写的I/O
rw=rw                    测试顺序混合写和读的I/O
bs=4k                    单次io的块文件大小为4k
bsrange=512-2048         同上,提定数据块的大小范围
size=5g                  本次的测试文件大小为5g,以每次4k的io进行测试
numjobs=30               本次的测试线程为30
runtime=1000             测试时间为1000秒,如果不写则一直将5g文件分4k每次写完为止
rwmixwrite=30            在混合读写的模式下,写占30%
rwmixread=30             在混合读写的模式下,读占30%
group_reporting          关于显示结果的,汇总每个进程的信息
name                     为测试任务指定一个名称

此外
lockmem=1g               只使用1g内存进行测试
zero_buffers             用0初始化系统buffer
nrfiles=8                每个进程生成文件的数量

场景:
1. 100%随机,100%读, 4K
fio -filename=/dev/sda1 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100read_4k
--filename=/dev/sda1: 测试目标是 /dev/sda1 分区。
--direct=1: 使用直接 I/O 模式,绕过系统缓存。
--iodepth=1: I/O 队列深度为 1,表示每次只发出一个 I/O 请求,等待完成后再发下一个。
--thread: 使用线程模式执行任务。
--rw=randread: 执行随机读操作。
--ioengine=psync: 使用同步 I/O 引擎。
--bs=4k: 每次 I/O 操作的数据块大小为 4KB。
--size=1000G: 总共测试 1000GB 的数据量。
--numjobs=50: 启动 50 个并行任务。
--runtime=180: 运行时间为 180 秒(3 分钟)。
--group_reporting: 输出汇总报告,显示所有任务的整体性能。
--name=rand_100read_4k: 测试任务名称为 rand_100read_4k

执行命令后,fio 将生成一份详细的测试报告,包括以下内容:

    读/写吞吐量:每秒读写的数据量(通常以 MB/s 或 IOPS 为单位)。
    延迟:I/O 操作的平均、最小、最大和百分位延迟时间。
    CPU 使用率:测试期间的 CPU 使用情况。
    错误率:报告任何 I/O 错误

=============================执行结果=============================================
rand_100read_4k: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
...
fio-3.7
Starting 50 threads
Jobs: 50 (f=50): [r(50)][100.0%][r=7958KiB/s,w=0KiB/s][r=1989,w=0 IOPS][eta 00m:00s]
rand_100read_4k: (groupid=0, jobs=50): err= 0: pid=11438: Mon Aug 19 17:31:38 2024
   read: IOPS=3787, BW=14.8MiB/s (15.5MB/s)(2668MiB/180349msec)
    clat (usec): min=7, max=1816.8k, avg=13190.06, stdev=58772.49
     lat (usec): min=7, max=1816.8k, avg=13190.12, stdev=58772.49
    clat percentiles (usec):
     |  1.00th=[     18],  5.00th=[     26], 10.00th=[     42],
     | 20.00th=[     52], 30.00th=[     78], 40.00th=[    163],
     | 50.00th=[    314], 60.00th=[    816], 70.00th=[   1876],
     | 80.00th=[   5735], 90.00th=[  23987], 95.00th=[  60556],
     | 99.00th=[ 250610], 99.50th=[ 400557], 99.90th=[ 792724],
     | 99.95th=[1010828], 99.99th=[1367344]
   bw (  KiB/s): min=    0, max= 2602, per=2.16%, avg=326.69, stdev=327.04, samples=14707
   iops        : min=    0, max=  650, avg=81.57, stdev=81.82, samples=14707
  lat (usec)   : 10=0.01%, 20=2.14%, 50=16.68%, 100=14.27%, 250=13.96%
  lat (usec)   : 500=8.17%, 750=3.90%, 1000=3.28%
  lat (msec)   : 2=8.37%, 4=6.49%, 10=6.84%, 20=4.73%, 50=5.31%
  lat (msec)   : 100=2.78%, 250=2.08%, 500=0.67%, 750=0.21%, 1000=0.06%
  cpu          : usr=0.01%, sys=0.05%, ctx=683994, majf=3, minf=305
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=683049,0,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
   READ: bw=14.8MiB/s (15.5MB/s), 14.8MiB/s-14.8MiB/s (15.5MB/s-15.5MB/s), io=2668MiB (2798MB), run=180349-180349msec

Disk stats (read/write):
  sda: ios=811179/484, merge=317/42, ticks=18406380/26023, in_queue=18442783, util=100.00%
=================================================================================



2. 100%随机,70%读,30%写 4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=randrw_70read_4k


3. 测试nfs等网络设备
其他不变, --directory=/mnt/nfs: 指定 NFS 挂载点作为测试目录

附录

判断进程文件读写方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1. strace
strace -e trace=lseek,read,write -p <pid>
	-e trace=lseek,read,write: 只跟踪 lseek、read 和 write 系统调用。
	<pid>: 目标进程的 PID
如果看到频繁的 lseek 调用,并且 read 或 write 操作在非连续的位置进行,这通常表明文件正在进行随机读写

2. dstat
dstat --top-io --top-bio
	--top-io: 显示进程 I/O 活动。
	--top-bio: 显示块设备 I/O 活动。
通过观察 I/O 活动的频率和模式,您可以推断文件是否在进行随机读写, 您提供的输出似乎是来自 dstat 或类似工具的报告,

如何判断随机读写:
在这个输出中,您可以看到与 I/O 操作相关的进程以及它们的 I/O 消耗情况。这些信息可以帮助您识别哪些进程可能正在执行随机读写:

> 频繁的小块 I/O 操作:如果一个进程执行了大量的小块读写操作(例如几千字节或几百字节),这通常表明该进程正在执行随机 I/O 操作,而不是顺序 I/O 操作。

> 块 I/O 的分散性:如果一个进程的块 I/O 操作非常分散,且数据量不是连续的大块数据,这也可能是随机 I/O 的一个指标

================================================================================
/usr/bin/dstat:2619: DeprecationWarning: the imp module is deprecated in favour of importlib and slated for removal in Python 3.12; see the module's documentation for alternative uses
  import imp
----most-expensive---- ----most-expensive----
     i/o process      |  block i/o process   
systemd    1497k  784k|systemd    1513k  679k
sshd       6403k  955k|nfsd          0    32k
python     3827k 9632B|systemd-jou   0   128k
sshd        583k  298k|nfsd          0    28k
sshd       6193k  728k|nfsd          0    20k
nvitop     3696k    0 |nfsd          0    32k
python     3799k 9500B|nfsd          0    24k
sshd       6020k  724k|systemd-jou   0   124k
python     4000k   12k|nfsd          0    32k
python     4000k   12k|nfsd          0    36k
sshd       6207k  731k|nfsd          0    16k
python     3836k 9632B|nfsd          0    40k
irqbalance  730k    0 |nfsd          0    36k
sshd       6022k  725k|systemd-jou   0   124k
nvitop     3696k    0 |java          0   220k
python     3799k 9498B|nfsd          0    32k
sshd       6389k  954k|nfsd          0    32k
...
...
================================================================================
分析输出:
1. I/O Process:列出了每个进程的 I/O 活动情况,包括读取和写入数据的大小。Python 脚本显然是最耗费 I/O 资源的进程之一。
2. Block I/O Process:列出了涉及到块设备的 I/O 操作,也就是直接读写磁盘的操作。系统守护进程(如 systemd 和 nfsd)似乎参与了大量的块 I/O 操作

读写操作时传输的数据块大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
strace:最直接的方式来查看每次读写操作的块大小,适用于进程级别的分析。
iostat、pidstat:适合整体系统或设备级别的分析,但不会直接显示每次操作的块大小。
perf、blktrace:适合深入分析块设备层面的 I/O 请求大小。


1. strace
strace -e trace=read,write -p 1234
显示每次 read 和 write 调用的参数,包括传输的数据大小
eg:
read(3, "data", 4096) = 4096
write(4, "data", 512) = 512


2. blktrace
sudo blktrace -d /dev/sdX -o - | blkparse -i -
	/dev/sdX:您想要监控的设备(例如 /dev/sda)。
	blkparse 解析输出,并显示每个 I/O 请求的详细信息,包括请求的大小
apt install blktrace
本文由作者按照 CC BY 4.0 进行授权