1. 项目概述:为什么需要测试磁盘读写速度?
在Linux服务器运维、性能调优或者日常开发中,磁盘I/O性能往往是整个系统中最容易被忽视却又至关重要的瓶颈。你可能遇到过这样的情况:数据库查询突然变慢,应用响应时间拉长,甚至系统出现卡顿,排查了一圈CPU和内存都正常,最后发现是磁盘“拖了后腿”。这时候,一个准确的磁盘读写速度测试,就是定位问题的“听诊器”。
“如何测试Linux磁盘的读写速度”这个标题,背后指向的是一个非常实际且高频的需求。它不仅仅是运行一个命令那么简单,而是涉及到测试方法的选择、测试参数的解读、测试结果的对比分析,以及如何将测试数据转化为优化决策。无论是评估新采购的SSD是否达到标称性能,还是排查生产环境中的I/O瓶颈,亦或是为数据库、虚拟化等I/O密集型应用规划存储方案,掌握一套可靠的磁盘测速方法论都是基本功。
我自己在多年的运维和架构工作中,无数次通过磁盘测速来验证硬件性能、诊断线上问题。我发现,很多朋友只知道用dd命令,但测出来的结果往往和实际体验相差甚远,或者看不懂hdparm、fio这些更专业工具的输出。这篇文章,我就来系统性地拆解一下在Linux环境下测试磁盘读写速度的完整流程、工具选型背后的逻辑,以及如何避开那些常见的“坑”,让你拿到真正有参考价值的性能数据。
2. 核心工具选型与适用场景解析
测试磁盘速度,工具的选择直接决定了结果的准确性和场景的匹配度。没有“银弹”工具,不同的工具适用于不同的测试目的。下面这张表清晰地对比了最常用的几款工具:
| 工具名称 | 测试类型 | 主要特点 | 适用场景 | 不适用场景 |
|---|---|---|---|---|
dd | 顺序读写 | 系统自带,简单粗暴。通过拷贝大文件来测试连续I/O。 | 快速验证磁盘大文件连续读写能力,例如备份、视频流处理。 | 测试随机I/O、IOPS、队列深度等复杂场景;结果受缓存影响极大。 |
hdparm | 顺序读(缓存/直接) | 专门用于ATA/IDE/SATA硬盘的工具,能测试带缓存和直接读的速度。 | 快速评估硬盘(尤其是机械硬盘)的原始顺序读取性能。 | 测试写性能;对NVMe SSD支持有限;测试随机I/O。 |
fio(Flexible I/O Tester) | 全场景(顺序/随机,读/写,同步/异步) | 功能极其强大的专业级I/O基准测试工具,可模拟任何I/O负载。 | 数据库、虚拟化、文件服务器等生产环境性能评估与瓶颈定位;压测。 | 命令行参数复杂,对新手不友好;需要较长时间运行。 |
ioping | 延迟(Latency) | 类似于网络ping,专注于测试磁盘I/O的响应延迟。 | 评估磁盘的响应速度,对于数据库、交易系统等延迟敏感型应用至关重要。 | 测试吞吐量(Throughput)和IOPS。 |
注意:
dd命令虽然方便,但它最大的问题是会利用操作系统的页面缓存(Page Cache)。如果你写一个文件然后立刻读,数据可能还在内存里,测出来的速度是内存速度,而不是真实的磁盘速度。这在评估真实性能时是一个巨大的误导。
为什么我强烈推荐掌握fio?因为真实世界的负载很少是纯粹的顺序读写。一个数据库服务器,既有顺序写日志(Redo Log),也有大量的随机读索引和数据页。一个Web服务器,可能同时服务许多小文件的随机读请求。fio的强大之处在于它能精确模拟这些混合负载,给出包括IOPS(每秒输入输出操作数)、带宽(Bandwidth)、延迟(Latency)在内的完整性能画像。这对于容量规划和性能调优来说,是dd和hdparm无法替代的。
3. 实战操作:从基础命令到专业压测
了解了工具,我们进入实战环节。我会从最简单的命令开始,逐步深入到复杂的场景模拟。
3.1 快速上手:使用dd和hdparm进行初步评估
当你需要快速对磁盘的连续读写能力有个大致了解时,这两个命令是首选。
使用dd测试写入速度:
# 测试写入速度:生成一个1GB的文件,观察耗时 dd if=/dev/zero of=./testfile bs=1M count=1024 oflag=direct conv=fdatasync- 命令拆解:
if=/dev/zero: 从“零设备”读取数据,提供无限的空字节流,避免数据源成为瓶颈。of=./testfile: 输出到当前目录的testfile文件。bs=1M: 设置每次读写的数据块大小为1MB。更大的块通常能获得更高的吞吐量。count=1024: 读写1024个块,总共1GB(1024 * 1MB)。oflag=direct:关键参数。使用直接I/O(Direct I/O),绕过操作系统的缓冲区缓存(Buffer Cache),让数据直接写入磁盘。这是获得真实写入速度的关键。conv=fdatasync:另一个关键参数。在命令结束前,强制将文件数据和元数据同步到磁盘。确保所有数据都落盘后才结束计时,否则dd可能在数据还在缓存时就报告完成,导致速度虚高。
- 结果解读:命令执行完毕后,会输出类似
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.12345 s, 210 MB/s的信息。这里的210 MB/s就是测得的平均写入速度。
使用dd测试读取速度:
# 首先确保有测试文件(如刚才生成的testfile),然后清空缓存再测试读速度 sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches' # 清除页面缓存、目录项和inode缓存 dd if=./testfile of=/dev/null bs=1M count=1024 iflag=directiflag=direct: 同样使用直接I/O读取,绕过缓存。- 清空缓存:测试读取前清除系统缓存至关重要,否则测出的可能是内存速度。
使用hdparm测试读取速度:
# 查看磁盘信息并测试带缓存读 sudo hdparm -I /dev/sda | grep -i model # 查看磁盘型号 sudo hdparm -Tt /dev/sda-T: 测试缓存(Buffer Cache)的读取速度。这基本是内存的速度,用于评估系统内存和总线的性能。-t: 测试设备(磁盘)的直接读取速度,会绕过缓存。这个数字更接近磁盘的真实顺序读取性能。- 结果会分别显示
Timing cached reads和Timing buffered disk reads的速度。
3.2 专业评估:使用fio进行全方位压测
fio的配置通常写在一个 job file(任务文件)里,这样参数清晰且可重复使用。下面我们创建一个基础的测试文件。
安装 fio:大多数Linux发行版都可以通过包管理器安装。
# Ubuntu/Debian sudo apt-get install fio # CentOS/RHEL sudo yum install fio创建并运行一个综合测试任务:新建一个文件,例如disk_test.fio,内容如下:
[global] ioengine=libaio # 使用Linux原生异步I/O引擎,效率最高 direct=1 # 使用直接I/O,绕过缓存 size=1G # 每个线程/进程使用的文件大小 runtime=30 # 每个测试项目运行时间(秒) directory=/mnt/test # 测试目录,请替换为你的测试挂载点 filename_format=fio_test.$jobname.$filenum [seq_write] name=顺序写测试 rw=write bs=1M iodepth=1 [seq_read] name=顺序读测试 rw=read bs=1M iodepth=1 [rand_write_4k] name=4K随机写测试 rw=randwrite bs=4k iodepth=32 # 提高队列深度以压测IOPS [rand_read_4k] name=4K随机读测试 rw=randread bs=4k iodepth=32运行测试:
sudo fio disk_test.fio参数深度解析:
ioengine=libaio: Linux上性能最好的异步I/O引擎,对于现代SSD和高速存储,必须使用异步I/O才能发挥其队列能力。direct=1: 和dd的oflag=direct作用一样,确保测试的是真实的磁盘I/O。iodepth:队列深度。这是理解存储性能的核心概念。你可以把它想象成一条高速公路上的车道数。iodepth=1意味着每次只发一个I/O请求,等这个请求完成后再发下一个(类似单车道)。iodepth=32意味着可以同时发出最多32个I/O请求(类似32车道)。对于NVMe SSD这种支持高并发的高性能设备,提高队列深度是榨取其最大IOPS潜力的关键。但对于机械硬盘,提高队列深度可能因磁头频繁寻道反而降低性能。bs:块大小。模拟不同的I/O模式。大块(如1M)测吞吐量(带宽),小块(如4k)测IOPS和延迟。数据库操作多以4K/8K/16K随机读写为主。rw: 定义了读写模式。write/read是顺序,randwrite/randread是随机。
结果解读:fio的输出非常详细。你需要重点关注以下几行:
seq_write: (groupid=0, jobs=1): err= 0: pid=12345: ... write: IOPS=105, BW=105MiB/s (110MB/s), ... (运行时间等) iops : min= 100, max= 110, avg=105.00, stdev= 2.00 bw (MiB/s) : min= 100, max= 110, avg=105.00, stdev= 2.00- IOPS: 每秒操作数。对于随机4K测试,这个值越高越好,直接反映了磁盘处理并发小请求的能力。
- BW (Bandwidth): 带宽,即吞吐量。对于顺序读写测试,这个值反映了磁盘传输大块数据的最大能力。
- lat (Latency): 延迟。包括
clat(完成延迟)和slat(提交延迟)。clat分布(如clat percentiles)对于评估服务稳定性尤其重要,它告诉你99%或99.9%的请求在多少毫秒内完成。数据库应用特别关注高百分位延迟(如P99.9)。
3.3 延迟专项测试:使用ioping
对于延迟敏感型应用,ioping能给你最直观的感受。
# 安装ioping # Ubuntu/Debian: sudo apt-get install ioping # CentOS/RHEL: 可能需要从EPEL源安装或编译 # 测试当前目录的I/O延迟 ioping -c 10 .-c 10: 发送10次请求。 输出会显示每次请求的响应时间,以及最小值、平均值、最大值。单位通常是微秒(us)或毫秒(ms)。一块好的NVMe SSD平均延迟可以低于100微秒,而机械硬盘则在数毫秒到十几毫秒。
4. 测试环境准备与关键注意事项
测试结果的准确性,一半取决于工具,另一半取决于测试环境。不注意以下要点,测试就失去了意义。
4.1 测试前的环境准备清单
- 选择正确的测试目标:务必在独立的、未使用的磁盘或分区上进行测试。不要在系统盘(尤其是根分区)满负荷运行时测试,系统自身的I/O会严重干扰结果。最好准备一块空白磁盘或新建一个分区。
- 卸载并重新挂载(可选但推荐):对于要测试的文件系统,可以先卸载
umount,再用-o discard(针对SSD)等选项重新挂载,确保文件系统状态干净。 - 避开缓存陷阱:如前所述,所有测试命令必须使用直接I/O(
direct=1,oflag=direct,iflag=direct)来绕过操作系统缓存。对于读测试,务必在测试前使用echo 3 > /proc/sys/vm/drop_caches清空缓存。 - 预热与稳态:特别是对于SSD,其性能可能在使用初期(空盘)和写入一段时间后(稳态)有差异。企业级测试通常要求先用
fio进行长时间的预处理(Preconditioning),使磁盘达到稳定状态后再测试。消费级测试可以忽略此步,但要知道空盘测出的速度可能是“最佳情况”。 - 多跑几次取平均:I/O性能存在波动,单次测试可能有偶然性。对每个测试场景,建议运行3-5次,去掉异常值后取平均。
4.2 理解你的存储设备
- 机械硬盘 (HDD):性能受磁头寻道时间和旋转延迟限制。顺序读写尚可(通常100-200 MB/s),但随机IOPS非常低(通常100-200)。提高
iodepth对提升其IOPS帮助不大,反而可能因排队增加延迟。 - SATA SSD:随机IOPS大幅提升(数万到十万级),顺序读写速度在500 MB/s左右(受SATA 3.0接口6Gbps带宽限制)。
iodepth可以适当提高(如32)。 - NVMe SSD:性能怪兽。随机IOPS可达数十万甚至百万级,顺序读写超过3 GB/s(PCIe 3.0 x4)或7 GB/s(PCIe 4.0 x4)。必须使用高队列深度(iodepth=64, 128甚至256)和多个工作线程(numjobs)才能压满其性能。使用
libaio引擎。
4.3 我的实操心得与避坑指南
dd命令的“秒完”假象:如果你用dd不加oflag=direct和conv=fdatasync,会发现写入一个10GB的文件“秒完”,速度显示几个GB/s。这绝对是假象,数据只写到了内存缓存就返回了。永远记得加上这两个参数来获取真实的写入速度。- 测试文件大小要足够:测试文件大小至少是系统内存的2-3倍,才能确保数据不会完全被缓存。例如,系统有16G内存,测试文件最好用32G或更大。对于
fio,可以用size=32G。 - 关注延迟分布,而不仅是平均值:平均IOPS高固然好,但如果延迟的P99.9(最慢的0.1%的请求)非常高,意味着你的应用偶尔会遭遇“卡顿”。这对于在线交易系统是致命的。
fio输出的clat percentiles一定要看。 - 模拟真实负载:不要只测顺序读写。根据你的应用场景设计测试。如果是MySQL数据库,重点测试
16k的随机读写和高队列深度。如果是Web服务器存放图片,可以测试128k左右的顺序读和一定比例的随机读。 - 小心“写放大”与性能衰减:测试SSD(特别是消费级TLC/QLC SSD)的写入性能时,长时间持续写入后速度可能会断崖式下降,这是缓存用尽或触发了垃圾回收(GC)。你的测试时长(
runtime)应该覆盖到应用可能遇到的长时写入场景。
5. 结果分析与性能瓶颈定位
拿到测试数据后,如何分析?这里提供一个简单的决策树:
顺序读写速度远低于预期(例如,NVMe SSD测出来只有1GB/s):
- 检查接口:使用
lspci | grep -i nvme或lsblk -d -o name,rota,size,model确认磁盘型号和接口。一块PCIe 4.0的SSD插在PCIe 3.0插槽上,速度会减半。 - 检查CPU占用:使用
top或iotop查看fio进程是否占满了一个CPU核心。单线程fio可能无法驱动高端SSD,尝试增加numjobs(并发任务数)来充分利用多核CPU和SSD的多个队列。 - 检查散热:高性能SSD过热会触发降频保护。触摸散热片或使用
sensors命令查看温度。
- 检查接口:使用
随机读写IOPS低:
- 检查队列深度(iodepth):这是最常见的原因。对于NVMe SSD,尝试将
iodepth从1逐步提高到64、128。观察IOPS是否随之增长直到饱和。 - 检查块大小(bs):确认测试的块大小是否符合你的场景。用
1M块测不出高IOPS。 - 检查I/O引擎:确认使用了
ioengine=libaio,并且系统支持(可能需要安装libaio库)。
- 检查队列深度(iodepth):这是最常见的原因。对于NVMe SSD,尝试将
延迟过高:
- 对比
ioping结果:如果ioping测出的基础延迟就很高,可能是硬件问题或驱动问题。 - 查看
fio的clat延迟分布:如果平均延迟低但P99.9延迟极高,说明磁盘存在“卡顿”,可能是固件问题、垃圾回收导致,或者是共享存储网络中的干扰。 - 检查系统负载:在测试期间,使用
iostat -x 1观察磁盘的util(利用率)和await(平均等待时间)。如果util持续接近100%,说明磁盘已是瓶颈。
- 对比
与标称值对比:将你的测试结果(顺序读/写、4K随机读/写IOPS)与磁盘官网的标称值对比。在正确的测试条件下(高队列深度、多线程、直接I/O),结果应该能达到标称值的70%-90%以上。如果差距巨大,就需要按上述步骤排查。
6. 进阶场景与脚本化实践
对于需要频繁测试或自动化集成的场景,将测试过程脚本化是高效的做法。
编写一个自动化测试脚本:你可以创建一个Shell脚本,自动执行清缓存、运行多种fio测试、并格式化输出关键结果。下面是一个简化示例的框架:
#!/bin/bash TEST_DIR="/mnt/test" # 修改为你的测试目录 OUTPUT_FILE="disk_benchmark_$(date +%Y%m%d_%H%M%S).log" echo "=== 磁盘性能基准测试 $(date) ===" | tee -a $OUTPUT_FILE echo "测试目录: $TEST_DIR" | tee -a $OUTPUT_FILE echo "" | tee -a $OUTPUT_FILE # 1. 清空缓存 echo "[1/5] 清空系统缓存..." sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches' # 2. 使用fio进行顺序读写测试 echo "[2/5] 运行顺序读写测试..." sudo fio --name=seq_write --rw=write --bs=1M --size=1G --iodepth=1 --ioengine=libaio --direct=1 --directory=$TEST_DIR --runtime=30 --output-format=json | jq '.jobs[0].write.bw' >> $OUTPUT_FILE # 类似地添加 seq_read, rand_write_4k, rand_read_4k 测试,并使用jq解析JSON输出中的bw, iops, lat_ns.mean等字段 # 3. 使用ioping测试延迟 echo "[5/5] 运行I/O延迟测试..." ioping -c 100 $TEST_DIR | grep -E "avg|min|max" >> $OUTPUT_FILE echo "" | tee -a $OUTPUT_FILE echo "测试完成!详细结果已保存至: $OUTPUT_FILE" | tee -a $OUTPUT_FILE cat $OUTPUT_FILE这个脚本使用了fio的JSON输出格式,并利用jq工具来精准提取我们关心的指标(带宽、IOPS、延迟),使得结果易于被其他程序解析和记录。你可以根据需求,扩展这个脚本,增加更多测试模式(如混合读写比例rwmixread)、不同块大小测试,甚至生成图表。
模拟真实应用负载:最有效的测试是模拟真实应用的I/O模式。例如,为MySQL设计一个测试job file:
[mysql_oltp] rw=randrw # 随机混合读写 rwmixread=70 # 70%读,30%写,模拟典型OLTP负载 bs=16k # InnoDB默认页大小 iodepth=16 # 适中的队列深度 numjobs=4 # 模拟4个并发连接 ioengine=libaio direct=1 size=10G # 总测试数据量 runtime=300 # 运行5分钟 group_reporting=1运行这个测试,你得到的数据对评估数据库服务器的磁盘性能具有直接的参考价值。
经过上面从工具选择、实战命令、环境准备到结果分析的完整流程拆解,你应该已经掌握了在Linux下专业地测试磁盘读写速度的方法。核心要点再回顾一下:用对工具(fio为主)、绕过缓存(direct)、设置合理的参数(iodepth,bs,numjobs)、理解结果(IOPS、带宽、延迟分布)并关联硬件特性。下次再遇到存储性能问题,你就可以拿出这套方法,像老中医一样,通过几个测试“方子”,快速准确地诊断出磁盘的“气血”到底足不足了。