首页 / 资讯中心 / 文章详情

Linux磁盘性能测试:用dd和hdparm快速诊断存储I/O瓶颈

Linux磁盘性能测试:用dd和hdparm快速诊断存储I/O瓶颈 ★ FEATURED ARTICLE
前几天凌晨两点接到电话客户那边数据库日志刷屏应用全部卡死。远程上去第一件事不是查SQL而是先看一眼磁盘到底什么状态因为经验告诉我很多慢得像蜗牛的系统根子都在存储I/O上。这时候我最先摸出来的工具永远都是dd和hdparm这两个老伙计。它们不是性能测试软件里最专业的却一定是排查现场最管用的。dd负责构造真实读写压力hdparm负责快速读取硬盘硬件能力一写一读配合起来五分钟之内就能判断磁盘有没有“带病上岗”给后面的优化争取时间。这篇分享适合所有Linux运维、DBA、存储工程师以及那些刚接触性能排查的初学者。我会把命令逐条拆开讲清楚包括为什么要加某个参数、数字怎么换算、结果怎么解读还会把我在现场踩过的几个坑一并说出来这些坑没有一次是白踩的希望你能直接绕过去。1. 为什么第一时间想到 dd 和 hdparm1.1 应急检测的“老两样”一提到磁盘性能测试很多人第一反应是装fio配置脚本、跑随机读写、出IOPS报告很专业可问题是你得先有fio而且配置格式还要花五分钟回忆。生产故障现场最缺的就是时间最不缺的是恐慌。dd几乎出现在每一台Linux服务器上hdparm稍微冷门一点但大部分发行版也自带即使没有一条yum install -y hdparm或者apt-get install -y hdparm就能解决不依赖复杂的编译环境不牵扯额外的内核模块干净利落。这两个工具还有一个共同特点它们测试的是顺序大块I/O能力。很多业务卡顿确实先表现为顺序读写的瓶颈比如数据库全表扫描、日志批量写入、备份文件传输这些场景下顺序吞吐量就是命门。所以用来做第一轮健康度筛查它们完全可以胜任。等到确认磁盘“可能有问题”再上fio这类重武器做精细化的随机I/O和延迟分析这样的排查路径效率最高。1.2 两个工具的分工完全不一样这是我见过最多人混淆的地方。hdparm主要面向块设备本身它可以查询硬盘参数、启停写缓存、设置高级电源管理性能测试只是它的附带功能-t参数直接从磁盘读数据绕过了文件系统这一层dd则是一个数据拷贝工具它既可以写文件到文件系统也可以读写裸设备测试范围更灵活。两者配合的逻辑非常清晰hdparm用来测“盘本身”的极限读取速度dd用来测“当前实际环境”下能跑出什么样的写速度和读速度。换句话说hdparm回答“这块盘大概能跑多快”dd回答“你这台机器当前配置下能跑多快”。两者有差距很正常如果差距过大说明瓶颈不在盘而在文件系统、阵列卡缓存策略、总线带宽或者内核参数。1.3 什么场景不适合用它们先泼一盆冷水。dd和hdparm测的都是顺序流测不出随机小I/O的延迟分布也模拟不了数据库那种大量并发、混合读写的实际压力。你拿它们测出一片漂亮的数字不代表你的数据库撑得住高峰期反过来数字很难看往往意味着盘真的有问题即使随机性能平时表现还行顺序都上不去的盘大概率也该换了。所以我把这两个工具定位成“急诊听诊器”而不是“影像科MRI”。要做存储选型、容量规划、压测调优还是老老实实上fio用runtime300、rwrandrw、iodepth32这样的补充测试再加上iostat和blktrace去深挖延迟指标。这篇分享的主旨正是告诉你怎么把听诊器用到极致。2. 测试前必须搞清的底层原理2.1 一条 dd 命令里的参数拆解dd的语法看起来简单实际上每个关键参数都踩过雷。最常见的写测试命令长这样dd if/dev/zero of/mnt/data/disk_test.img bs1M count2048 convfdatasync拆开看if指定输入文件这里用/dev/zero生成无限零字节不会受源盘读取速度干扰of指定输出文件一般放到你要测试的目标挂载点下面bs1M表示每次读写1MiB的数据块这是顺序测试常用的块大小太小了测出来的不是盘的速度而是系统调用的开销count2048表示传输2GiB数据至于为什么是这个量级后面细说最容易被忽略的是convfdatasync它强制在命令结束前把文件数据落盘确保数字反映的是真实写入性能而不是页缓存里的“假写”。很多人会问bs1M count2048最终写入多大早期我用过一个土办法bs1M count2048传入strace看实际字节数其实不用这么麻烦直接用dd --help查看说明或者自己在心里算2048块乘以1MiB等于2048MiB约2.15GB。这个数量级是有讲究的如果只写100MB结果会被磁盘自带缓存和文件系统缓存完全吃掉测出来的数字能飙到几千MB/s完全失真。还有一个参数也值得写进测试命令oflagdirect它让dd绕过页缓存直接写设备和convfdatasync目的类似但实现方式不同。两者的选择看场景oflagdirect更接近物理设备真实速度但要求bs和底层扇区对齐有些老文件系统不兼容convfdatasync更通用先写到缓存再同步落盘兼顾真实性和兼容性适合绝大多数现场。我个人的习惯是第一遍用convfdatasync如果怀疑结果虚高再加oflagdirect复测一次。2.2 hdparm 的 -t 和 -T 为什么结果差这么多hdparm的读性能测试有两个经典参数一个是-t一个是-T。写过几千次命令之后我发现大多数人从没认真看手册里的解释导致数字出来以后一头雾水。hdparm -t /dev/sda hdparm -T /dev/sda-t测的是从磁盘实际读取数据的速率这个过程中数据会经过Linux页缓存但在读取时会尽量利用设备自身的扇区缓存-T测的是从内存缓存中读取数据的速率它反映的主要是CPU、内存、总线和缓冲区管理的性能跟磁盘本身的关系不大。所以你会看到-T的数字通常比-t高出一个量级服务器内存带宽动辄几万MB/s而一块机械盘的物理极限也就是两百多MB/s。很多人拿-T的数字去证明磁盘很快这就是典型的把裤腰当领带完全用错了地方。更专业的做法是给-t加上--direct参数变成hdparm -t --direct /dev/sda。这一下就绕过了文件系统页缓存让磁盘控制器直接和设备通信数字更接近硬件真实能力。我第一次在SSD上跑这个命令时数字比不带--direct低了不少一度以为是盘坏了后来想明白之前的“高速”其实是在消费已经预读进内存的数据。所以记住要测硬盘物理读性能-t --direct才是正经姿势。2.3 直写模式与页缓存为什么测出来“假快”Linux内核会尽量用空闲内存做文件缓存你往磁盘写数据时数据首先进入内存页缓存内核再异步回写到磁盘。这个过程本身没有问题问题出在测试工具上。如果你执行dd if/dev/zero of/mnt/data/test.img bs1M count2048而不加convfdatasync或者oflagdirectdd把数据交给页缓存就返回了整个耗时可能只有几百毫秒计算出来的速率是内存速率而不是磁盘速率。读测试同样有这个问题。第一次读取某个文件时数据会从磁盘进入页缓存第二次再读同一个文件几乎全部命中缓存速度翻几倍毫不奇怪。曾经有个同事拿着测试数据跟我说盘有800MB/s的读能力那是块SATA SSD我让他先echo 3 /proc/sys/vm/drop_caches清理页缓存再测一遍数字立刻掉到500MB/s左右。这个操作在生产库上最好不要乱用因为会牺牲所有缓存热数据但测试环境下想得到真实结果就必须面对缓存这个“作弊器”。另一种思路是直接测字符设备或块设备。裸设备的读取不走文件系统页缓存结果更干净但风险也更大一个参数写错可能把盘上的数据抹掉。所以我在生产机上更推荐用文件系统加convfdatasync的组合既安全又能反映真实使用场景。3. 实操过程与完整命令序列3.1 测试前的环境确认动手之前先花一分钟看环境这一步能避免后面出现灾难性错误。我通常执行三条命令lsblk df -h cat /proc/meminfo | grep MemTotallsblk确认盘符对应的设备名特别注意那种机器上有好几块盘的情况千万别把系统盘当成测试对象df -h确认挂载点剩余空间至少要有测试文件的三倍余量防止磁盘写满引发文件系统异常看内存则是为了估算页缓存的影响范围内存越大缓存对短时长测试的干扰越明显。如果测试对象是已经承载业务的服务器还需要确认当前磁盘I/O压力。可以直接快速看一眼iostat -x 1 3如果%util已经接近100%那你测出来的数字是“挤出来”的不是真实水平最好先和业务方确认窗口期再做。我见过有人不管三七二十一直接开测结果数据难看得很查了半天才发现是另一个定时任务正在跑全量备份白白浪费时间。3.2 hdparm 读测试实战找一块没有业务写入的盘如果你只想做健康检查在系统盘上做只读测试是安全的因为这个测试不修改数据。命令如下hdparm -t --direct /dev/sda一块SATA机械盘上常见输出是/dev/sda: Timing buffered disk reads (O_DIRECT) 486 MB/sec这个486MB/s对于机械盘来说明显偏高很可能是设备有较大缓存或者磁盘本身是混合盘。如果数字跑到1200MB/s以上基本可以判定是SSD或者带缓存阵列。要注意的是hdparm在部分云主机和虚拟化环境下会显得无效因为它直接发ATA命令给磁盘而虚拟机磁盘控制器往往不响应这类命令报错“HDIO_DRIVE_CMD(identify) failed”时不要慌这是环境特性不代表磁盘坏了换dd继续测就行。为了降低偶然性我习惯连续测三次取中位数for i in 1 2 3; do hdparm -t --direct /dev/sda | grep Timing; done数字波动在10%以内都算正常如果三次结果忽高忽低差值超过30%就要怀疑磁盘有坏道、固件在做后台清理或者链路不稳定。3.3 dd 写测试实战接下来写测试这是整个流程里风险最高的环节。我的铁律是写测试永远只写在文件系统挂载点下新建的临时文件上绝不直接写裸设备。测试完立即删除临时文件。dd if/dev/zero of/mnt/data/.disk_test_$$.img bs1M count2048 convfdatasync rm -f /mnt/data/.disk_test_$$.img加$$是为了让文件名带上当前进程号避免并发测试时多个进程写到同一个文件。count2048意味着写入2GiB对于常见SSD耗时也就两三秒对于慢速机械盘可能需要二三十秒这个时长足够让磁盘脱离缓存进入稳态。如果测试时间太长可以适当调低count但最低不要低于512否则结果没有参考价值。执行完你会看到类似这样的输出20480 records in 20480 records out 2147483648 bytes (2.1 GB, 2.0 GiB) copied, 6.53412 s, 329 MB/s最后一行的329MB/s就是顺序写吞吐量。这个数字是否正常得结合磁盘类型判断。如果是SATA SSD329MB/s偏低但还算合理如果是NVMe SSD那几乎可以断定有问题常见NVMe写速度都应该在1000MB/s往上。3.4 dd 读测试实战读测试有两种做法一种是读刚才写的文件一种是直接读裸设备。读文件的好处是安全不涉及无关数据但要注意顺序写测试完成后立刻读数据可能还在页缓存里测出来是内存速度所以要先清缓存。清缓存需要root权限echo 3 /proc/sys/vm/drop_caches然后执行dd if/mnt/data/.disk_test_$$.img of/dev/null bs1M count2048读文件的数字代表“文件系统层看到的速度”包含了文件系统元数据开销。如果想更纯粹地测盘可以用dd if/dev/sda of/dev/null bs1M count2048这个命令直接读取磁盘前2GiB数据不经过文件系统但会读到磁盘的前部区域那里通常是分区表和启动引导不能反映整盘特性。更公平的做法是先parted看分区起始位置再用dd从指定偏移读取但这套操作对新手来说过于复杂而且读取裸设备时的skip参数一旦写错可能会读到敏感数据区域所以我只在专业测试时用快速排查时读临时文件就够了。3.5 结果换算与多次采样现场还有一种情况就是你知道测出来的数字对不对但别的同事问起“你这个顺序写多少IOPS”你得知道怎么换算。顺序I/O场景下的公式非常简单IOPS 吞吐量(MB/s) * 1024 / 块大小(KB)如果测出500MB/s块大小是4KB那么IOPS就是500*1024/4128000。但这里有个陷阱顺序测试的块是1MB换算成4KB的随机IOPS毫无意义因为顺序和随机的物理开销完全不同。所以正确的做法是就着你的数据类型来说话测试文件系统迁移时用大块顺序指标测试数据库日志盘时用小块同步写指标。多次采样方面我一般会跑三轮取中间那次数同时注意每次测试之间间隔至少几秒钟让磁盘控制器内部队列清空。如果三次数值差距大我会再看磁盘的SMART信息smartctl -a /dev/sda重点关注Reallocated_Sector_Ct和Current_Pending_Sector这两个指标异常往往说明盘内部已经有物理坏块测试数字不稳定是正常的备件可以提前申请了。4. 结果解读与快速定位4.1 典型数值分档参考表为了让快速判断更有依据我把自己在常见设备上的实测经验整理成一张参考表。这些数字不是规格书上的峰值而是真实环境下带文件系统开销的典型值不同固件和驱动会有出入但作为初步定位足够了设备类型顺序读(MB/s)顺序写(MB/s)备注机械盘 7200rpm SATA120~200100~180读写差别不大写略低机械盘 10000rpm SAS180~260150~230企业盘缓存策略影响明显入门级SATA SSD400~550300~500写速受SLC缓存影响大中高端NVMe SSD2500~70001500~5000看PCIe代际和型号RAID5阵列(4块SATA SSD)800~1200500~800写惩罚导致写明显低于读注意这个表是“有缓存策略加持”的常见结果不是绝对标准。同一块盘文件系统是ext4还是xfs挂载参数有没有noatime都能影响最终数字。所以更靠谱的方式是拿同型号健康盘在同一环境跑一遍同样的命令做横向对比那才是真正可信的基准。4.2 结果异常时从哪里查起如果dd测出来的写速度只有几十MB/s别急着给磁盘判死刑按照下面的顺序排查能省掉很多冤枉路。第一步查链路状态。lspci看磁盘控制器是不是跑在预期速率上NVMe盘插在PCIe 3.0 x4插槽上理论带宽约3500MB/s如果降到x1模式速度直接砍到不到900MB/s。第二步查磁盘固件和日志dmesg | grep -i error看有没有大量I/O错误一条ata bus error往往预示着线缆松动或盘即将损坏。第三步查阵列卡策略很多RAID卡默认开启写缓存掉电后可能丢数据有些场景下管理员会强制关闭写缓存导致写性能断崖式下滑这时候要在阵列卡管理界面确认缓存策略。第四步再回到应用层看看是不是文件系统碎片太多、磁盘空间剩余不足5%、还是iostat中await飙升而svctm正常回答清楚这些磁盘背锅的冤案就少了很多。5. 实测中踩过的坑5.1 把测试写在系统盘上差点挤爆根分区有一年给客户做迁移评估临时挂载点不够用我图省事直接把测试文件放到了/根目录下。/dev/zero写出来的零字节文件是稀疏的但dd写入的是全量数据不会自动稀疏化2GiB文件很快把根分区剩余空间吃了大半导致系统日志服务开始报磁盘满各种应用出现间歇性卡顿。后来我养成了习惯写测试之前先看挂载点剩余空间并且测试文件名一律带.test后缀设置crontab每天自动清理超过一天的.test文件。5.2 写裸设备把分区表擦掉只能重建这个坑最痛。当时要在客户服务器上对一块没有挂载的“空盘”做性能测试我想当然认定它没有数据直接执行了dd if/dev/zero of/dev/sdb bs1M count1024。测试倒是顺利完成随后客户才告诉我说那块盘上保存着旧备份。由于分区表已被清零数据恢复软件扫了好几天才找回大部分文件。那次之后我立了一条规矩除非能明确百分之百确认盘上无数据且已经过书面确认否则禁止用dd写裸设备。用lsblk -f查看文件系统信息后还有疑虑就宁可把盘拔下来插到测试机上去测绝对不在生产环境边界模糊的盘上做写测试。5.3 清理缓存误伤了数据库热数据有一次为了测真实读速度我在一台正在运行业务的数据库服务器上执行了echo 3 /proc/sys/vm/drop_caches结果缓存清理后数据库缓存命中率骤降SQL查询延迟明显上升业务方立刻收到了告警。幸好影响只持续了十几分钟缓存重新预热后恢复但那次事件被写进了事故复盘报告过程极其尴尬。正确的打开方式是做这样的测试前先确认该主机没有承载核心在线业务如果必须测就利用业务低峰期并且提前和团队报备。5.4 单次测试误判性能没有多次采样我还遇到过因为单次测试数字不理想直接投诉供应商硬盘质量的情况。第一次dd写测只跑出250MB/s供应商换了一块盘结果还是一样最后查出来是文件系统挂载参数里barrier1导致的写入延迟和盘本身毫无关系。单次测试的偶然因素太多机械盘外圈和内圈速度能差30%SSD垃圾回收周期会周期性吃掉一段性能系统后台任务也会抢资源。所以现在哪怕只是快速测试我也会至少跑三遍尽量在同一个时间段完成避免拿到“假故障”数据。6. 常见问题与排查速查表6.1 为什么 hdparm 测出的数字比 dd 高那么多hdparm测的是设备层读取极限没有文件系统开销还可能在读取时命中了磁盘自身的缓存dd测的是文件系统到应用层的完整链路包含了写文件、分配元数据、目录更新等开销二者差异大完全正常。判断磁盘健康时以dd的结果为准更贴近实际业务hdparm的数字主要用于验证盘的硬件上限。6.2 为什么同一块盘两次 dd 结果差出两倍最常见的原因就是页缓存。第一次写数据时数据还留在缓存里第二次复测时直接复用了缓存结果读取测试更明显第二次读完全命中内存。解决方法是清理页缓存或者在不同文件上重复测试。另一个原因是测试时间点不同机械盘在不同磁道的位置速度差很多文件系统碎片也会放大这种差距。6.3 convfdatasync 和 oflagdirect 有什么区别二选一还是都用两者都是为了让测试结果真实落盘。fdatasync是命令结束后调用一次fsync它的开销集中在最后一步测试过程本身还是在用缓存oflagdirect是绕过缓存直接写持续消耗真实I/O资源。二选一推荐fdatasync兼容性最好对结果有怀疑时再用oflagdirect验证。两个一起用时要注意文件系统是否支持直接I/O部分网络文件系统不支持命令会直接报错。6.4 能不能在数据库服务器上直接跑 dd 测试可以但有条件。选择业务低峰期尽量在独立的挂载点上测试避免和数据库文件放在同一文件系统测试前用iostat确认当前I/O压力不大清理缓存的操作必须谨慎或者干脆不清缓存而是采用冷文件方式测试也就是先写一个文件等几分钟后再读这样即使有缓存数字也不会失真太多。6.5 什么情况下应该放弃 dd 和 hdparm 改用专业工具当你要为采购选型出具报告、要评估数据库IOPS能力、要定位延迟毛刺问题时dd和hdparm给不了你足够细的数据前者是顺序大块测试后者只有读测试。这时候直接上fio用--rwrandrw、--bs4k、--iodepth32、--numjobs8这样的组合模拟真实随机负载才能获得可以做量化决策的数据。记住快速测试是为排查服务的最终结论一定要靠更严谨的基准工具来支撑。6.6 排查指令速查表目的命令注意事项查看磁盘与分区信息lsblk -f先确认测试对象查看实时I/O压力iostat -x 1 5%util接近100%时结果不可信测试磁盘读速度hdparm -t --direct /dev/sda虚拟机环境下可能不支持清理页缓存echo 3 /proc/sys/vm/drop_caches生产环境谨慎执行测试文件写速度dd if/dev/zero of/path/test bs1M count2048 convfdatasync临时文件务必清理测试文件读速度dd if/path/test of/dev/null bs1M count2048测前写文件并等待冷却检查磁盘SMART信息smartctl -a /dev/sda关注坏块计数检查内核I/O报错dmesg | grep -i error连续报错立即停测这套组合拳打下来磁盘健康状态基本心里有数了。最后再分享一个我自己的习惯测试结果我会记到运维笔记里配合当时的iostat截图和文件系统挂载参数一起归档。下次哪个应用再报慢我会先翻出历史基线数据对比一眼就能看出磁盘性能是“一如既往”还是“突然劣化”这个习惯帮我免掉了无数次重复测试。磁盘性能排查不是跑一条命令就完事的事工具越简单越考验使用者对系统原理的理解希望这篇分享能让你下一次遇到存储问题的时候心里更有底。
阅读完成 · 觉得有帮助?
咨询建站