Linux主机性能测试方法
背景
最近打算用躺家吃灰的树莓派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
对于读性能测试,我们一般可以用 hdparm 工具(hard disk parameter? hardware device parameter?)。Debian下直接 apt 安装即可:
$ sudo apt install hdparm -y
hdparm目前只支持磁盘读性能测试,提供了三种方式进行测试:
- 直接读内存:
sudo hdparm -T [device]
。 - 带buffer读磁盘:
sudo hdparm -t [device]
。 - 不带buffer读磁盘:
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
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的确还是快,不过还是没啥参考意义。考虑到实际情况下大部分程序都是采用 fdatasync 的模式来写,因此我们在比较时用这个数据即可。
读性能
当然,有人也会利用 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
。
网络
网速测试一般分两种,一种是测试当前设备对普通公网设备的读写速度;另一种是点对点测试两个服务器之间的速度。
speedtest
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,不要慌,多试几下一般就好了 。
iperf3
如果我们并不是想测试公网网速,而是测试两个服务器之间点对点的网速。这时用 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
对于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 似乎有坑,测试出来的结果异常的大,不具有参考价值。
md5sum
虽然 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 进行以下对比,我们就会发现一些神奇的现象:
Cortex-A72(ARM)
- sysbench 单线程:1479.99 event/s
- dd + md5sum:184 MB/s
Neoverse-N1(ARM)
- sysbench 单线程:3497.70 event/s
- dd + md5sum:424 MB/s
Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz(x86_64)
- sysbench 单线程:820.19 event/s
- dd + md5sum:409 MB/s
Intel(R) Xeon(R) CPU E5-26xx v4(x86_64)
- sysbench 单线程:927.74 event/s
- dd + md5sum:459 MB/s
Intel(R) Xeon(R) Platinum 8255C CPU @ 2.50GHz(x86_64)
- sysbench 单线程:1054.30 event/s
- dd + md5sum:515 MB/s
可以发现 ARM 架构的机器在 sysbench 上表现几乎都比 X86_64 的机器好很多,但是实际跑 md5sum 却相差不大甚至差不少。
可见不同架构间二者的指标并不完全正相关;不过相同架构间二者的指标还是基本正相关的。