最近打算用躺家吃灰的树莓派4B搭一个NAS,用来快捷方便地访问和备份一些资源。由于备选的硬件(芯片、硬盘、网线、路由器等)和软件(内网穿透技术)的技术选型比较多,这时候就需要有一个能简单评估服务性能的方法。因此简单搜寻了一下常见方案,方便在技术选型时有个统一的对比标准,并且对一些常见指标能在数量级上有一些感性的理解。
对于硬盘的读写速度测试,首先我们需要注意根据读写的实现细节不同,测试出的结果会有很大的差别。例如对于读来说,是否走缓存读、缓存的大小如何;对于写来说,是否只写缓存、是否同步等待刷盘、刷盘的时机如何,等等。
在实际测试的时候一定要明确自己使用的是哪种IO模式,否则就会得到一些似是而非的结论。
在测试硬盘前,我们首先得知道我们有哪些硬盘、分别对应哪些分区。用 lsblk
(list block)命令可以查看当前机器下挂载的块设备:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 29.3G 0 disk
└─sda1 8:1 1 29.3G 0 part /media/pi/5615-BDE2
mmcblk0 179:0 0 59.5G 0 disk
├─mmcblk0p1 179:1 0 256M 0 part /boot
└─mmcblk0p2 179:2 0 59.2G 0 part /
可以看到,这里的 sda (SATA device a) 表示我外部插入的一个U盘;mmcblk0 (Multimedia card block 0) 表示树莓派自带的一张 SD 卡。这两个类型是 disk,也就是实体磁盘。
每个 disk 会被分成多个 partition,也就是这里的 sda1 和 mmcblk0p1、mmcblk0p2。每个 partition 又会 mount 到不同的文件夹下,用于在文件系统中进行访问。因此对于文件系统本身来说,我们只会关心到 partition 层面。
通过 df
命令我们也能直接观察到所有分区的挂载情况:
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 59G 11G 46G 19% /
devtmpfs 3.5G 0 3.5G 0% /dev
tmpfs 3.7G 0 3.7G 0% /dev/shm
tmpfs 3.7G 65M 3.6G 2% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 3.7G 0 3.7G 0% /sys/fs/cgroup
/dev/mmcblk0p1 253M 32M 221M 13% /boot
tmpfs 738M 4.0K 738M 1% /run/user/1000
/dev/sda1 30G 23M 30G 1% /media/pi/5615-BDE2
同时,disk 和 partition 的详细信息也可以通过 fdisk
命令查看:
$ sudo fdisk -l
Disk /dev/mmcblk0: 59.5 GiB, 63864569856 bytes, 124735488 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x140cee6b
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 8192 532479 524288 256M c W95 FAT32 (LBA)
/dev/mmcblk0p2 532480 124735487 124203008 59.2G 83 Linux
Disk /dev/sda: 29.3 GiB, 31457280000 bytes, 61440000 sectors
Disk model: ProductCode
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xf3203eea
Device Boot Start End Sectors Size Id Type
/dev/sda1 2048 61439999 61437952 29.3G 7 HPFS/NTFS/exFAT
总之,在这里我们只需要搞清楚我们想测试的磁盘和分区分别是哪个即可。
对于读性能测试,我们一般可以用 hdparm 工具(hard disk parameter? hardware device parameter?)。Debian下直接 apt 安装即可:
$ sudo apt install hdparm -y
hdparm目前只支持磁盘读性能测试,提供了三种方式进行测试:
sudo hdparm -T [device]
。sudo hdparm -t [device]
。sudo hdparm -t --direct [device]
。以我的 mmcblk0 设备为例,跑出来结果分别如下(当然,每次测试建议跑多次取平均值,这里偷个懒):
$ sudo hdparm -T /dev/mmcblk0
/dev/mmcblk0:
Timing cached reads: 1840 MB in 2.00 seconds = 921.43 MB/sec
$ sudo hdparm -t /dev/mmcblk0
/dev/mmcblk0:
Timing buffered disk reads: 130 MB in 3.04 seconds = 42.74 MB/sec
$ sudo hdparm -t --direct /dev/mmcblk0
/dev/mmcblk0:
Timing O_DIRECT disk reads: 124 MB in 3.01 seconds = 41.17 MB/sec
显然,走内存读是飞快,不过对于测试磁盘性能来说没有任何意义;不带buffer看起来比带buffer要慢一点点,差别不太大;考虑到现实场景中大多数都是带buffer的读,因此我们在比较时用带buffer读的结果来进行参考即可。
dd (data definition? data duplicator?) 是进行磁盘操作、文件生成之类的常用工具。在 gnu 的 coreutils 下,类 Unix 发行版几乎都自带。
一般我们会用 dd 来进行磁盘写性能测试,一般来说也有三种方式:
dd bs=1M count=256 if=/dev/zero of=test
。dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
。dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
。还是以我的 mmcblk0 设备为例(当前目录即挂载的 mmcblk0 设备),跑出来结果分别如下(当然,每次测试建议跑多次取平均值,这里还是偷个懒):
$ dd bs=1M count=256 if=/dev/zero of=test
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 1.39574 s, 192 MB/s
$ dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 31.739 s, 8.5 MB/s
$ dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 39.694 s, 6.8 MB/s
$ rm test
可见写内存不sync的确还是快,不过还是没啥参考意义。而由于 SD 卡本身写入速度就不高,因此这里 fdatasync 和 dsync 的差别不太大,如果是用更快的设备,这两个的差别会更大。考虑到实际情况下大部分程序都是采用 fdatasync 的模式来写,因此我们在比较时用这个数据即可。
前几天发现有的业余测评UP主会在 1 的基础上加上 status=progress 参数来实时测写入速度,看起来还挺专业:
$ dd if=/dev/zero of=test status=progress bs=1M
为了方便文本展示,我把 '\r' 替换成 '\n' 以打印每一次刷新:
$ dd if=/dev/zero of=test status=progress bs=1M 2>&1 |tr -s '\r' '\n'
200278016 bytes (200 MB, 191 MiB) copied, 1 s, 199 MB/s
401604608 bytes (402 MB, 383 MiB) copied, 2 s, 200 MB/s
602931200 bytes (603 MB, 575 MiB) copied, 3 s, 201 MB/s
805306368 bytes (805 MB, 768 MiB) copied, 4 s, 201 MB/s
1007681536 bytes (1.0 GB, 961 MiB) copied, 5 s, 201 MB/s
1210056704 bytes (1.2 GB, 1.1 GiB) copied, 6 s, 202 MB/s
1309671424 bytes (1.3 GB, 1.2 GiB) copied, 17 s, 77.0 MB/s
1455423488 bytes (1.5 GB, 1.4 GiB) copied, 18 s, 80.9 MB/s
1563426816 bytes (1.6 GB, 1.5 GiB) copied, 20 s, 78.0 MB/s
1750073344 bytes (1.8 GB, 1.6 GiB) copied, 60 s, 29.2 MB/s
1860173824 bytes (1.9 GB, 1.7 GiB) copied, 72 s, 25.8 MB/s
1966080000 bytes (2.0 GB, 1.8 GiB) copied, 82 s, 24.0 MB/s
2051014656 bytes (2.1 GB, 1.9 GiB) copied, 98 s, 20.8 MB/s
2162163712 bytes (2.2 GB, 2.0 GiB) copied, 101 s, 21.4 MB/s
2250244096 bytes (2.3 GB, 2.1 GiB) copied, 113 s, 20.0 MB/s
2357198848 bytes (2.4 GB, 2.2 GiB) copied, 117 s, 20.1 MB/s
2459959296 bytes (2.5 GB, 2.3 GiB) copied, 129 s, 19.1 MB/s
2558525440 bytes (2.6 GB, 2.4 GiB) copied, 139 s, 18.4 MB/s
2656043008 bytes (2.7 GB, 2.5 GiB) copied, 152 s, 17.5 MB/s
2754609152 bytes (2.8 GB, 2.6 GiB) copied, 170 s, 16.2 MB/s
2850029568 bytes (2.9 GB, 2.7 GiB) copied, 182 s, 15.6 MB/s
2960130048 bytes (3.0 GB, 2.8 GiB) copied, 187 s, 15.8 MB/s
3064987648 bytes (3.1 GB, 2.9 GiB) copied, 201 s, 15.2 MB/s
3178233856 bytes (3.2 GB, 3.0 GiB) copied, 223 s, 14.3 MB/s
3300917248 bytes (3.3 GB, 3.1 GiB) copied, 235 s, 14.0 MB/s
3371171840 bytes (3.4 GB, 3.1 GiB) copied, 247 s, 13.6 MB/s
3460300800 bytes (3.5 GB, 3.2 GiB) copied, 259 s, 13.4 MB/s
3552575488 bytes (3.6 GB, 3.3 GiB) copied, 262 s, 13.6 MB/s
3668967424 bytes (3.7 GB, 3.4 GiB) copied, 276 s, 13.3 MB/s
3764387840 bytes (3.8 GB, 3.5 GiB) copied, 289 s, 13.0 MB/s
3872391168 bytes (3.9 GB, 3.6 GiB) copied, 300 s, 12.9 MB/s
3954180096 bytes (4.0 GB, 3.7 GiB) copied, 303 s, 13.0 MB/s
4066377728 bytes (4.1 GB, 3.8 GiB) copied, 329 s, 12.4 MB/s
4173332480 bytes (4.2 GB, 3.9 GiB) copied, 332 s, 12.6 MB/s
4251975680 bytes (4.3 GB, 4.0 GiB) copied, 353 s, 12.0 MB/s
4387241984 bytes (4.4 GB, 4.1 GiB) copied, 355 s, 12.4 MB/s
4513071104 bytes (4.5 GB, 4.2 GiB) copied, 371 s, 12.2 MB/s
4582277120 bytes (4.6 GB, 4.3 GiB) copied, 372 s, 12.3 MB/s
4652531712 bytes (4.7 GB, 4.3 GiB) copied, 377 s, 12.3 MB/s
4811915264 bytes (4.8 GB, 4.5 GiB) copied, 387 s, 12.4 MB/s
4869586944 bytes (4.9 GB, 4.5 GiB) copied, 388 s, 12.6 MB/s
4979687424 bytes (5.0 GB, 4.6 GiB) copied, 406 s, 12.3 MB/s
5100273664 bytes (5.1 GB, 4.8 GiB) copied, 411 s, 12.4 MB/s
5181014016 bytes (5.2 GB, 4.8 GiB) copied, 419 s, 12.4 MB/s
5307891712 bytes (5.3 GB, 4.9 GiB) copied, 420 s, 12.6 MB/s
5356126208 bytes (5.4 GB, 5.0 GiB) copied, 422 s, 12.7 MB/s
5462032384 bytes (5.5 GB, 5.1 GiB) copied, 436 s, 12.5 MB/s
5557452800 bytes (5.6 GB, 5.2 GiB) copied, 450 s, 12.3 MB/s
5667553280 bytes (5.7 GB, 5.3 GiB) copied, 463 s, 12.2 MB/s
5750390784 bytes (5.8 GB, 5.4 GiB) copied, 485 s, 11.9 MB/s
5892997120 bytes (5.9 GB, 5.5 GiB) copied, 495 s, 11.9 MB/s
5975834624 bytes (6.0 GB, 5.6 GiB) copied, 513 s, 11.6 MB/s
6086983680 bytes (6.1 GB, 5.7 GiB) copied, 515 s, 11.8 MB/s
6180306944 bytes (6.2 GB, 5.8 GiB) copied, 517 s, 12.0 MB/s
6287261696 bytes (6.3 GB, 5.9 GiB) copied, 530 s, 11.9 MB/s
6370099200 bytes (6.4 GB, 5.9 GiB) copied, 532 s, 12.0 MB/s
6490685440 bytes (6.5 GB, 6.0 GiB) copied, 542 s, 12.0 MB/s
6550454272 bytes (6.6 GB, 6.1 GiB) copied, 545 s, 12.0 MB/s
6658457600 bytes (6.7 GB, 6.2 GiB) copied, 563 s, 11.8 MB/s
6755975168 bytes (6.8 GB, 6.3 GiB) copied, 576 s, 11.7 MB/s
6856638464 bytes (6.9 GB, 6.4 GiB) copied, 592 s, 11.6 MB/s
7010779136 bytes (7.0 GB, 6.5 GiB) copied, 601 s, 11.7 MB/s
7055867904 bytes (7.1 GB, 6.6 GiB) copied, 603 s, 11.7 MB/s
7158628352 bytes (7.2 GB, 6.7 GiB) copied, 615 s, 11.6 MB/s
7265583104 bytes (7.3 GB, 6.8 GiB) copied, 631 s, 11.5 MB/s
^C
测试了整整十分钟,发现展示出来的速率硬生生从 200MB/s 降到了 11MB/s。事实上如果我愿意等,展示出来的速率还会再降。而且即使是最后展示的这个速率看起来已经低了不少,其实他也远比实际的速率要大很多,因为当我按 Ctrl+C 终止测试时,仍然有大量的数据没有真正落盘,整个程序仍然 hold 了很久才终止。最后真正落盘所消耗的时间显然是没有统计在前面计算的速率中的。
当然,有人也会利用 dd 进行读性能测试,比如:
$ sudo dd bs=1M count=256 if=/dev/mmcblk0 of=/dev/null
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 6.03649 s, 44.5 MB/s
看起来很美好,结果也和 hdparm 差不多。但是当你第二次再跑这个命令的时候,由于读缓存的存在,结果会快特别多:
$ sudo dd bs=1M count=256 if=/dev/mmcblk0 of=/dev/null
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 0.267236 s, 1.0 GB/s
显然这样的测试是没有意义的。考虑到这种测试方法甚至很难做到幂等,这里还是不建议用 dd 来测试读性能。
对于磁盘读性能测试,建议使用 sudo hdparm -t [device]
。
对于磁盘写性能测试,建议使用 dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
。当然, bs 和 count 也可以适当改大以进一步提高准确性。
网速测试一般分两种,一种是测试当前设备对普通公网设备的读写速度;另一种是点对点测试两个服务器之间的速度。
speedtest 工具在各地都有测速服务器,通过命令行(speedtest-cli)或者网页(https://speedtest.cn,https://speedtest.net)都可以进行网速上下行的测试。这里以命令行为例:
$ sudo apt install speedtest-cli -y
$ speedtest-cli
Retrieving speedtest.net configuration...
Testing from China Mobile (183.192.82.69)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by Chinamobile-5G (Shanghai) [8.49 km]: 6.054 ms
Testing download speed................................................................................
Download: 128.24 Mbit/s
Testing upload speed......................................................................................................
Upload: 22.88 Mbit/s
虽然多次测试可能会访问到不同的测试点、导致结果有区别,不过其实也大差不差了。
在使用时偶尔会遇到返403,不要慌,可以先多试几下,如果还是不行,可以加下 --secure
参数(参考Reddit) 。
如果我们并不是想测试公网网速,而是测试两个服务器之间点对点的网速。这时用 iperf3 工具就好。
$ sudo apt install iperf3 -y # Debian 下
$ brew install iperf3 # MacOS 下
需要注意,除了 iperf3 之外,还有一个 iperf。这两个版本分别由不同组织开发,前后也不兼容。虽然似乎 iperf3 有坑,不过似乎功能多一点,尤其是支持了下行带宽测试(iperf 只支持上行带宽测试),所以这里还是用 iperf3。
iperf3 是 C/S 架构,服务端开启 server ,客户端开启 client,然后互相通信进行测速。以我在家的树莓派和一个在 HK 的 Azure 主机为例:
$ iperf3 -s -p 5555 # azure 主机上开启 server
$ iperf3 -c 104.208.65.181 -p 5555 # pi 上开启 client 并连接 server
测试完成后,client 上会有报告:
$ iperf3 -c 104.208.65.181 -p 5555
Connecting to host 104.208.65.181, port 5555
[ 5] local 192.168.1.2 port 35994 connected to 104.208.65.181 port 5555
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 8.68 MBytes 72.8 Mbits/sec 0 2.95 MBytes
[ 5] 1.00-2.00 sec 1.25 MBytes 10.5 Mbits/sec 2018 252 KBytes
[ 5] 2.00-3.00 sec 2.50 MBytes 21.0 Mbits/sec 1076 286 KBytes
[ 5] 3.00-4.00 sec 3.75 MBytes 31.5 Mbits/sec 861 237 KBytes
[ 5] 4.00-5.00 sec 2.50 MBytes 21.0 Mbits/sec 99 187 KBytes
[ 5] 5.00-6.00 sec 1.25 MBytes 10.5 Mbits/sec 0 206 KBytes
[ 5] 6.00-7.00 sec 2.50 MBytes 21.0 Mbits/sec 0 215 KBytes
[ 5] 7.00-8.00 sec 2.50 MBytes 21.0 Mbits/sec 0 218 KBytes
[ 5] 8.00-9.00 sec 2.50 MBytes 21.0 Mbits/sec 0 218 KBytes
[ 5] 9.00-10.00 sec 2.50 MBytes 21.0 Mbits/sec 0 220 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 29.9 MBytes 25.1 Mbits/sec 4054 sender
[ 5] 0.00-10.09 sec 26.5 MBytes 22.1 Mbits/sec receiver
iperf Done.
这里可以看出 client 对 server 的上行带宽大约是 22Mbit/sec。
类似的,server配置不变,client加上 -R 参数后可以测试出 server 对 client 的下行带宽:
$ iperf3 -c 104.208.65.181 -p 5555 -R
Connecting to host 104.208.65.181, port 5555
Reverse mode, remote host 104.208.65.181 is sending
[ 5] local 192.168.1.2 port 36000 connected to 104.208.65.181 port 5555
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 6.47 MBytes 54.3 Mbits/sec
[ 5] 1.00-2.00 sec 25.7 MBytes 216 Mbits/sec
[ 5] 2.00-3.00 sec 13.2 MBytes 111 Mbits/sec
[ 5] 3.00-4.00 sec 16.3 MBytes 137 Mbits/sec
[ 5] 4.00-5.00 sec 12.4 MBytes 104 Mbits/sec
[ 5] 5.00-6.00 sec 14.4 MBytes 121 Mbits/sec
[ 5] 6.00-7.00 sec 14.0 MBytes 117 Mbits/sec
[ 5] 7.00-8.00 sec 13.9 MBytes 116 Mbits/sec
[ 5] 8.00-9.00 sec 11.5 MBytes 96.7 Mbits/sec
[ 5] 9.00-10.00 sec 11.3 MBytes 95.2 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.09 sec 142 MBytes 118 Mbits/sec 2560 sender
[ 5] 0.00-10.00 sec 139 MBytes 117 Mbits/sec receiver
iperf Done.
这里可以看出 server 对 client 的下行带宽大约是 117Mbit/sec。
对于CPU和内存的性能测试,可以使用 sysbench 工具。
$ sudo apt install sysbench -y # Debian 下
$ brew install sysbench # MacOS 下
对于我的树莓派测试如下:
CPU单线程测试,可以看出单核每秒操作数大约1483:
$ sysbench cpu --threads=1 run
sysbench 1.0.18 (using system LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 1
Initializing random number generator from current time
Prime numbers limit: 10000
Initializing worker threads...
Threads started!
CPU speed:
events per second: 1483.17
General statistics:
total time: 10.0002s
total number of events: 14839
Latency (ms):
min: 0.67
avg: 0.67
max: 1.88
95th percentile: 0.68
sum: 9992.91
Threads fairness:
events (avg/stddev): 14839.0000/0.00
execution time (avg/stddev): 9.9929/0.00
内存读写测试,可以看出读写速度约是 1814MiB 每秒:
$ sysbench memory run
sysbench 1.0.18 (using system LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 1
Initializing random number generator from current time
Running memory speed test with the following options:
block size: 1KiB
total size: 102400MiB
operation: write
scope: global
Initializing worker threads...
Threads started!
Total operations: 18590983 (1858174.07 per second)
18155.26 MiB transferred (1814.62 MiB/sec)
General statistics:
total time: 10.0001s
total number of events: 18590983
Latency (ms):
min: 0.00
avg: 0.00
max: 0.20
95th percentile: 0.00
sum: 4463.57
Threads fairness:
events (avg/stddev): 18590983.0000/0.00
execution time (avg/stddev): 4.4636/0.00
需要注意的是,对 MacOS 的 CPU benchmark 似乎有坑,测试出来的结果异常的大,不具有参考价值。
虽然 sysbench 的基准测试看起来比较靠谱,但是实际环境下,真正的执行效率还跟执行的指令啥的都有挺大关系。比如,我们以执行 md5 的速度来对比 CPU 的执行效率:
$ dd if=/dev/zero bs=1M count=1024 | md5sum
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.81996 s, 184 MB/s
cd573cfaace07e7949bc0c46028904ff -
通过 dd
命令向 md5sum
持续发送 1GB 的数据进行计算,计算的速度也可以看成是 CPU 单核性能的一种指标。(考虑到管道操作是单线程,这个指令其实也只能用到一个核)
然后,如果我们多找几个 CPU 进行以下对比,我们就会发现一些神奇的现象:
可以发现 ARM 架构的机器在 sysbench 上表现几乎都比 X86_64 的机器好很多,但是实际跑 md5sum 却相差不大甚至差不少。
可见不同架构间二者的指标并不完全正相关;不过相同架构间二者的指标还是基本正相关的。