☰
dd与hdparm实战:快速摸清Linux磁盘性能
2026/10/15 4:21:33 网站建设 项目流程

正巧这几天在帮某实验室处理几台新到货的机器,里面既有NVMe固态盘也有老旧的SATA机械盘,团队里有个同事问了一句:“怎么快速确认这批盘的性能到底什么水平?”我的第一反应就是:先别急着上fio那种重型工具,dd加hdparm这两件套,十分钟之内就能把顺序读、顺序写、还有裸盘的真实读速摸个大概。尤其是做存储选型、怀疑磁盘IO卡顿、或者刚接手一台来历不明的服务器时,这两个系统自带的老工具往往比很多花里胡哨的测试脚本更直接。

这篇文章我打算把dd和hdparm的完整用法、参数背后的原理、测出来的数字怎么解读、以及我在实际测试中踩过的几个坑一次性讲清楚。内容偏实操,适合刚接触Linux运维的初学者,也适合那些平时用fio但想快速验证结果的老手。文章不会扯太深的内核细节,但会尽量把“为什么这样测”和“为什么那样测是错的”讲明白。

1. 什么时候需要把磁盘性能“测个明白”

1.1 最常见的几类测试需求

磁盘性能测试这个需求,听起来像是存储工程师的专属工作,但实际上普通运维和开发碰到的频率非常高。我自己遇到过的典型场景大概有这么几类。

第一类是新设备验收。机器刚上架,硬盘是新的,厂商标称的连续读写在宣传页上写得很好看,但到手之后是不是那回事,没人敢打包票。尤其是批量采购的机器,每块盘体质还有差异,抽几块跑一下顺序读写,等于给这批硬件的性能做个底档。

第二类是故障排查前的性能摸底。系统突然变卡,数据库查询慢,应用报IO超时,这时候你手上没有历史监控数据,最直接的办法就是先测一下盘本身还正不正常。如果顺序读只有正常水平的十分之一,那大概率是硬件出了问题;如果盘速正常,那问题就出在上层,可能是文件系统、业务负载或者锁竞争,方向完全不一样。

第三类是云主机和物理机的选型对比。我之前帮一家小公司对比两个云服务商的同规格主机,价格差了一倍,配置看起来完全一样,最后就是用dd做了几轮顺序写测试,数据差异一目了然,比看参数表靠谱得多。

1.2 先明确:你要测的是“磁盘”还是“整条I/O链路”

在动手敲命令之前,有一个概念必须先理清,否则很容易测完数据也不知道怎么解释。

dd和hdparm测出来的结果,到底代表什么?严格来说,测试结果受很多层因素影响:磁盘固件本身的性能、磁盘接口(SATA/NVMe)的带宽、操作系统IO调度策略、文件系统日志、甚至mount参数都会影响最终读数。你在文件系统里写临时文件测出来的速度,和直接读原始块设备测出来的速度,是两个层面的事情。

如果目标是评估“这块盘硬件本身行不行”,那就尽量绕开文件系统,直接测裸盘或者用iflag=direct、oflag=direct绕过页面缓存;如果目标是评估“这台机器当前实际可用性能”,那就在文件系统层面用普通文件测,甚至最好选在业务高峰之外的时间段,测出来的结果才接近用户真实感受。

这一点建议心里先有个数。下文所有命令我都会标注它测的是哪一层,配套的坑也会一并说明。

2. dd测速的完整姿势:参数选择决定测试是否可信

2.1 写速度测试的正确打开方式

dd测写速度,网上的经典命令是这样的:

dd if=/dev/zero of=./testfile bs=1M count=1024

这条命令确实能跑,但它测出来的数字,说实话参考价值很低。问题出在dd默认的写入流程上:它把数据从用户态写到内核的页面缓存(page cache)就返回了,而页面缓存最终落盘是后台异步完成的。换句话说,这条命令测的是“往内存里写”的速度,而不是“往磁盘上写”的速度。机器内存越大,这个假象越严重。

要测真实的写盘速度,必须在写入行为上做文章。我日常用的命令是这样:

dd if=/dev/zero of=./testfile bs=1M count=2048 oflag=direct conv=fdatasync status=progress

拆开解释一下几个关键参数。

oflag=direct表示打开文件时使用O_DIRECT标志,数据会直接从用户态缓冲区写到磁盘,绕过页面缓存,这一步就把“假内存速度”问题解决掉了。不过注意一点,O_DIRECT要求写入缓冲区内存对齐,而dd自己能处理好,所以普通使用你不用担心对齐问题。

conv=fdatasync表示数据传输完成后,调用fsync强制把所有数据真正落盘再返回。就算你用oflag=direct,某些文件系统或存储设备还是可能有写缓存缓冲,加这一层等于上了双保险。

status=progress会在过程中持续打印已经拷贝的字节数和当前速率,方便你估算整体耗时,不用干等。

这里有朋友会问,bs=1M, count=2048意味着总共写2GB,是不是越多越好?理论上测试文件越大越能反映稳定性能,因为SSD有SLC缓存机制,小文件测试往往测的是缓存内速度,一超出缓存容量就开始掉速。我自己的习惯是:SSD测4GB到8GB,机械盘测2GB就够,再多纯属浪费时间。

bs(块大小)的选择也有讲究。顺序大块传输用1M很合理,它贴近日常大文件拷贝的场景;如果你想模拟数据库那种小IO场景,可以试试bs=8k或bs=16k,但那种场景下性能会明显下降,属于正常现象。bs的值还会影响时间,机械盘上用太小的块做顺序写,时间会成倍增加,没必要。

我再多说一句关于oflag=dsync的用法。也有人推荐这个参数,它表示每次写入都同步一次,对机械盘来说这个代价非常大,测出来的速度会低到离谱,而且并不贴近日常使用场景,所以我不建议把它当默认选项。日常用oflag=direct加conv=fdatasync就足够了。

2.2 读速度测试:绕开缓存才能看到真实盘速

写测试有页面缓存的坑,读测试也有,而且更隐蔽。

你看下面这条命令测读速:

dd if=./testfile of=/dev/null bs=1M count=2048

第一次跑,数据确实是从磁盘读上来的,但读一遍之后,整个文件的内容可能已经留在页面缓存里了。如果你紧接着再跑第二次、第三次,后面的数据其实全部命中内存,速度可以飙到每秒好几GB——那不是磁盘的真实水平,那是内存的速度。不少新人拿到这种虚高数据还高兴半天,实际上跟盘一点关系都没有。

正确的读测试有两种做法。第一种是用iflag=direct绕过缓存:

dd if=./testfile of=/dev/null bs=1M count=2048 iflag=direct status=progress

这样每次读都直接走磁盘,不受缓存影响。第二种是直接读裸设备:

sudo dd if=/dev/sdb of=/dev/null bs=1M count=4096 iflag=direct status=progress

裸设备读测试有一个额外好处:它完全不涉及文件系统,能更干净地反映底层盘的真实读能力,适合用来做硬件层面的性能评估。

还有一个细节值得注意。如果你打算连续跑三次取平均,第2.1节写测试创建的那个临时文件一定要保留,后面的读测试都用同一个文件,这样才能做到“写读对照”——同一条数据链路,看着它写进去,再看它读出来。

2.3 用文件还是裸设备:一个容易被忽略的选择

关于测试介质,我的实际建议是:如果目标盘上有重要数据,那就老老实实创建测试文件,别碰裸设备;如果目标盘本身就是一块空盘或专门用来跑测试的盘,直接上裸设备会更干净。

为什么这么说?文件系统这个东西本身会引入额外开销。拿ext4举例,写一个1GB的测试文件,除了数据本身,你还要写文件系统的inode、block bitmap、日志;如果日志模式是journal,元数据还要单独写一份journal区域。这些都会体现在dd的总耗时里。所以文件层面测出来的写速,一定略低于裸盘层面的写速,两者有差异是正常的,差异特别大(比如超过20%)才值得警惕。

裸设备测试的命令是这样:

sudo dd if=/dev/zero of=/dev/sdb bs=1M count=2048 oflag=direct status=progress

这个命令会破坏目标盘上的所有数据,使用前务必确认目标盘是一块可以随时覆盖的空盘,并且对设备名反复核对。我有一个习惯:测试前先跑lsblk看一眼盘符、容量、挂载点,再动手。

另外,文件系统本身的不同也会带来差异。XFS在顺序大文件读写方面通常略优于ext4,而ext4在元数据操作上更保守;不是哪家绝对好,而是你要清楚测出来的数据包含了文件系统的特征。我自己做硬件验收时,习惯裸盘测一次、XFS文件系统上再测一次,两层数据对照,既能看出硬件水平,也能看出文件系统开销。

3. hdparm读速测试:先搞清楚它在测什么

3.1 -t和-T背后分别是哪条路径

hdparm是个老牌磁盘工具,名字有点唬人,但它最常用的功能其实非常简单:测读速。命令长这样:

sudo hdparm -t /dev/sdb

跑完之后会输出类似这样的一行:

Timing buffered disk reads: 512 MB in 3.01 seconds = 170.12 MB/sec

新手看这个数字,最容易产生的疑问是:“为什么比dd测出来的读速低/高?”要解释这一点,得先搞明白hdparm -t到底测的是什么路径。

hdparm -t的作用是“对设备读取进行计时”,它走的是O_DIRECT路径,直接读块设备,绕过文件系统、绕过页面缓存。所以它测的是磁盘设备本身的顺序读能力,干净利落。上一次分区格式化之前,这机械盘顺序读速度是170MB/s,说明盘本身状态在线;而dd文件层面的读速如果只有120MB/s,差出来的部分就是文件系统开销和碎片的影响。

hdparm -T的用途完全不同:

sudo hdparm -T /dev/sdb

它测的是“缓存读取速度”,实际上是从内存的页面缓存里读数据,数字可以高达几千MB/s,反映的是内存子系统的速度,不是磁盘。所以-T更适合用来判断缓存是否生效、系统内存读取是否正常,别拿它代表磁盘性能。

我实际工作中用hdparm最多的场景,就是快速做裸盘读速的横向对比。比如一台机器有六块盘,我想确认它们速度有没有差异,直接对每块盘跑一遍hdparm -t,不到一分钟就能看出有没有“拖后腿”的盘。前阵子我就靠这个抓出了一块读写明显比同类盘慢一截的故障盘,后来验证是SMART信息里已经有重映射警告了。

3.2 顺便用hdparm多查看几项磁盘状态

hdparm除了测速,还有几个参数我建议顺手用一用,对于快速了解磁盘健康状态很有帮助。

sudo hdparm -I /dev/sdb

-I会输出一大段磁盘的身份信息,包括型号、固件版本、支持的传输模式、是否支持TRIM等等。看这一段输出,我就知道这盘是什么年代的产物,有没有启用高级电源管理。对于老机械盘尤其要注意电源管理设置,某些硬盘会因为节能策略频繁启停磁头,导致性能忽高忽低。

sudo hdparm -C /dev/sdb

-C查看磁盘当前的电源状态,输出active/idle就是正常工作,输出standby说明盘处于休眠状态。有时候你测速发现盘速极低,先查一眼是不是刚被唤醒,等到状态稳定再测,结论才有意义。

还要提醒一句,hdparm本身也支持设置参数(比如-W开关写缓存,-S设置休眠时间),但这些功能我基本不用,理由很简单:现代内核和设备通常已经配置了合理参数,手动改反而容易引发数据安全问题。测速的话,-t、-T、-I、-C这四个足够用了。

4. 测出来的数字到底怎么解读:缓存、对齐和调度器

4.1 为什么第一次测速永远最快

很多人测试的时候会遇到一个明显规律:同一块盘,第一次跑出来的速度比后面几次都要快,尤其SSD上特别明显。这背后主要有两个原因。

第一个原因是页面缓存预热,这个前面提过。文件一旦被读过一次,就会留在内核的内存缓存里,之后的读测试直接命中内存,那数字根本不能代表磁盘。所以如果你想要“稳定的、可复现的结果”,读测试务必要加iflag=direct或者用hdparm -t,没有第二个选项。

第二个原因只影响写测试,是SSD独有的“SLC缓存”机制。现在市面上的消费级和企业级SSD,主控会在盘上划出一部分区域模拟SLC模式,利用它写入速度快的特性作为“加速缓冲区”。当你写入的数据量超过SLC缓存容量,主控就要把数据搬进TLC/QLC区域,这期间速度会明显掉下来。所以同样的盘,写1GB时能跑到1GB/s,写16GB时可能就只有500MB/s了。

知道这个机制之后,你再看网上那些“SSD写速突破2GB/s”的测试图,就得学会多问一句:测了多少数据量?如果就测了1GB,那很可能测的是缓存速度,参考意义要打个折扣。这也是我坚持测试数据量至少4GB的原因。

4.2 结果忽高忽低:从IO队列和调度器找原因

有时候你会发现,同一个命令跑三次,结果一次比一次低,或者高低差距超过15%,这并不代表盘不稳定,更常见的原因是测试没有独占IO路径。

磁盘测试最理想的状态是:这块盘上没有其他业务读写,系统也没有后台任务在扫盘。但现实往往不是这样。日志服务、监控采集、病毒扫描、文件索引,这些程序随时可能冒出来读写一阵子,直接把你的测试结果搅浑。我自己遇到过一次,测试期间有logrotate在轮转日志,写速直接掉了30%。

要定位这类干扰,我习惯在跑测速的同时,另开一个终端执行:

iostat -x 1

重点看%util和await两列。如果%util长期接近100%,说明磁盘一直处于忙碌状态,这时的测速结果不准确;如果await忽高忽低,说明IO队列里有人在插队。找到元凶之后,等空闲了再测,或者干脆换个时间段。

还有一个干扰项藏在操作系统里:IO调度器。不同调度器对顺序读写的调度策略不同,但现代内核默认配置一般影响不大。如果你在老的发行版上跑测试,可以在测试前确认一下当前调度器:

cat /sys/block/sdb/queue/scheduler

输出可能是none、mq-deadline或kyber。对SSD来说none通常是最合适的(直接让设备自己处理队列),对机械盘mq-deadline能保证读写请求的公平性。不要盲目修改生产环境的调度器,但你要心里清楚,不同机器之间的测速对比,最好保证调度器配置一致,否则对比没有意义。

4.3 一个容易被低估的干扰项:块大小对齐

关于SSD性能,有一个非常经典却容易被忽略的因素:分区是否4K对齐。我自己早期就吃过这个亏。

当时给一台老机器装系统,分区工具用的默认参数,没手动对齐扇区,结果那块SSD的随机写性能只有对齐后的一半不到。后来重新分区再测,速度立刻恢复正常。对于新买的盘,现代分区工具默认都是对齐的,但要小心那种“从别的机器拆下来的老盘”,分区表还是旧格式的,很可能没对齐。

检查方法也比较简单:

cat /sys/block/sdb/queue/optimal_io_size cat /sys/block/sdb/queue/minimum_io_size

还有lsblk -t也能看到对齐信息。如果确认没对齐,解决方法通常是重新分区,但会丢数据,操作前必须备份。这个坑在多盘服务器和克隆盘上特别常见,测速之前花几秒钟看一眼,能省掉很多排查时间。

5. 一次靠谱测速的完整流程和实测中踩过的坑

5.1 相对稳妥的测速流程

说了一堆原理和注意事项,我把自己平时执行的一套流程整理出来,你照着做就能得到一组相对可信的数据。假设目标盘是/dev/sdb,已经格式化并挂载在/mnt/data:

第一步,先确认盘的基本信息和状态:

lsblk -d -o NAME,SIZE,MODEL,ROTA /dev/sdb sudo hdparm -I /dev/sdb | grep -i "trim" sudo hdparm -C /dev/sdb

第二步,裸盘读速测试:

sudo hdparm -t /dev/sdb

第三步,在文件系统层面创建测试文件并测写速:

cd /mnt/data && dd if=/dev/zero of=./perf.test bs=1M count=4096 oflag=direct conv=fdatasync status=progress

第四步,测文件层面的读速:

cd /mnt/data && dd if=./perf.test of=/dev/null bs=1M count=4096 iflag=direct status=progress

第五步,重复第三步和第四步各两三次,每次测试前把文件删掉重建(避免文件系统碎片和缓存影响),记录每次结果,取中位数,丢掉明显偏离的异常值。

第六步,测试完成后清理现场:

rm -f /mnt/data/perf.test && sync

这个流程看起来简单,但每个步骤都有目的,不是随随便便凑出来的。如果你只是想做粗略对比,第三步和第四步就够;如果你要验收一批盘,建议把裸盘测试和文件测试都做了,数据留在表格里备查。

5.2 我在实际测试中踩过的坑

这么多年下来,我在磁盘测速上翻过几次车,每次都挺印象深刻,这里挑几个拿来说说。

第一个坑是拿系统盘测写速。有次我在一台业务机器上跑写测试,忘了看挂载点就把临时文件写到了根分区,结果还没跑完,那台机器的系统盘空间被一个2GB的测试文件塞满了,直接导致服务异常。从那以后,我写测试一定会先确认当前路径所在的分区,并且测试文件命名带明显前缀(比如perf.test),防止误删。

第二个坑是内存比磁盘还大。有台机器有64G内存,我为了省事只测了1GB的文件,结果读速数据漂亮得不像话,后来才反应过来整块文件都留在内存里了,那根本不是盘的速度。从那以后我给自己定了个规矩:文件大小至少要超过物理内存的一半,同时加iflag=direct,两条做到一条才放心。

第三个坑更隐蔽,是写缓存造成的“突发快”。有些硬盘(尤其是早期的机械盘和企业盘)板载写缓存非常激进,dd看时间是很快,但数据其实还在盘上缓存里没落到介质上。这种“快”经不起考验,断电就完蛋。所以我的测试命令里一直带着conv=fdatasync,宁可在最后多等两秒钟,也要确认数据真落盘了才算数。

第四个坑说起来有点丢人,有次我在一台测试机上连续测了三块SATA盘,前两块都是200MB/s级别,第三块死活跑不到100MB/s,我一度怀疑是盘坏了。后来才发现是第三块盘之前一直在做坏道扫描,还没结束就开始测速。测试期间别让磁盘“兼职”干别的活,这是最基本的纪律,那次是个反面教材。

5.3 结果解读参考

最后给一组我自己总结的参考区间,方便你拿到数字之后快速判断(数据基于常见环境,不同平台会有波动):

测试场景机械盘(SATA)入门级SATA SSDNVMe SSD
顺序写(1M块)120~200 MB/s350~500 MB/s800~3000 MB/s
顺序读(1M块,direct)150~250 MB/s400~550 MB/s1000~7000 MB/s
4K随机写(块8k)1~5 MB/s80~200 MB/s更依赖QD,不适用dd

如果你的测试结果大幅低于这个区间,先检查缓存有没有绕开、有没有别的进程在抢IO、盘是不是快满了;如果这些都排除了,那就要考虑硬件层面的问题,比如线缆松动、盘片老化、固件故障,该换就换。

顺带提一句,dd和hdparm测的都是“顺序大IO”能力,它们能很好回答“这块盘最大能跑多快”的问题,但回答不了“数据库这样的随机小IO场景会不会卡”。真要评估随机读写、队列深度、延迟分布,还得用fio这类更专业的工具。不过那是另一个话题了,日常快速摸底,dd加hdparm这套组合拳已经完全够用。

最后分享一个我在实操中的体会:磁盘测试这件事,最忌讳的就是“跑了一个命令,看到一个数字,就下结论”。数字背后的条件(缓存绕没绕开、数据量多大多小、有没有干扰进程)比数字本身重要得多。把这套流程固化下来,每次都用同样的条件测,你的数据才具有横向对比的价值,也才能在盘出问题时第一时间发现端倪。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询