磁盘读写测试这块,iozone是绕不开的一个老牌工具。它能在文件系统层面测出顺序读写、随机读写、重写、复读等一整套性能数据,命令行参数多但逻辑清晰。这篇文章就把iozone的下载安装、核心命令参数、完整测试流程和常见坑一次性讲透,适合做运维、存储选型、性能调优的朋友参考。
我做性能测试这几年,磁盘工具从dd一路用到fio,最后发现日常最快出结论的还是iozone。一条命令能跑完大部分主流场景,输出结构化数据,不管给领导汇报还是自己分析都够用。今天这篇不讲废话,只讲怎么用、怎么避开坑。
1. 认识iozone:为什么磁盘性能测试绕不开它
1.1 iozone是什么,能解决什么问题
iozone是一个跨平台的文件系统基准测试工具,最早由Don Capps在SGI工作时开发,后来开源并持续维护,官网在iozone.org。它做的事情核心就一件:在指定目录下创建文件,然后以不同的方式读写这些文件,最后把每秒传输的字节数算出来。跟dd这类工具相比,iozone不是测“一次性写多少最快”,而是组合出几十种读写模式,把场景覆盖得很全。
实际工作中它能派上用场的地方不少。比如采购服务器前对比两块磁盘的真实水平,新挂载的文件系统做上线前验证,云主机租的云盘规格到底够不够,甚至排查“磁盘变慢了”这类问题。我经常把它当成磁盘性能的体检仪:先跑一遍自动模式,拿到一组基准数据,再针对具体场景做细化测试,问题基本能定位个七八成。
iozone还有一个特点:它是在文件系统层面工作的,不是直接往块设备上写。这意味着测试结果包含文件系统开销,比如ext4和xfs在同样的磁盘上跑出来会有差异。这个特性有时候被当成缺点,但反过来看,它更接近业务实际——应用读写的是文件,不是裸盘。
1.2 iozone、dd、fio该怎么选
很多人上来就问:有dd和fio,为什么还要用iozone。我的看法是工具各有侧重点,搭配着用效率最高。
dd的问题是太“单薄”,它只能测顺序写或顺序读的整块搬运速度,对随机小IO、混合读写这些完全没有建模能力。hdparm偏向硬件层,测SATA盘还行,换到文件系统场景就力不从心。fio确实强大,IO模型、队列深度、延迟分布都能控制,但配置复杂,光命令行参数就得记半天,适合做深入压测。
iozone正好卡在中间:它比dd专业得多,比fio简单得多。一条-a参数就能把文件大小、记录大小、读写模式组合成矩阵自动跑完,输出结果一眼能看懂。我的习惯是先用iozone做快速摸底,发现瓶颈或者需要更细的数据时,再上fio做针对性压测。
1.3 下载与安装:源码编译还是包管理器
iozone的获取方式按平台分几种。最推荐的是从官网下载源码自己编译,过程不复杂。官网是iozone.org,进入Downloads页面会看到针对不同平台的源码包,文件名类似iozone-3-510.tar,下载后解压即可。
Linux下的编译路径很清晰。解压后进入src/current目录,直接执行make linux,几分钟就能编出可执行文件。需要注意的是,iozone编译完不需要make install,生成的iozone可执行文件就在src/current目录下,直接从命令行调用即可。如果需要大文件支持,可以在编译前给CFLAGS加上大文件宏,64位系统一般不用管,但32位系统跑大文件测试时务必注意这一点。
如果你的系统用包管理器,那更方便。Debian/Ubuntu系直接apt install iozone3,CentOS/RHEL系用yum或dnf install iozone。装好后命令行输入iozone -v能看到版本号就说明环境正常。Windows环境可以用官方提供的预编译exe,或者用Cygwin自己编译,不过Windows用户建议优先考虑WSL或虚拟机里测,兼容性和结果稳定性会好很多。
注意:源码编译本身占不了多少空间,但测试时文件会很大,建议测试目录预留充足空间,后面会详细说这个坑。
2. 解剖iozone的测试模式与命令参数
2.1 核心测试模式逐一拆解
iozone通过-i参数指定测试模式,常用的编号含义如下:
- 0 write/re-write:写新文件,再重写已有文件
- 1 read/re-read:读新文件,再重复读
- 2 random-read/random-write:随机读写
- 3 random-backwards-read:随机反向读
- 4 record-rewrite:记录重写,也就是修改已有文件的内容
- 5 stride-read:跳跃读,按固定跨距跳过部分区域
- 6 fwrite/re-fwrite:使用C库fwrite函数写
- 7 fread/re-fread:使用C库fread函数读
- 8 mixed-mindir:混合读写
日常最关心的是write/re-write、read/re-read、random-read/write这三组。顺序读写代表大文件拷贝、备份还原这类场景,随机读写对应数据库、小文件服务等场景。我自己做存储选型时,必跑的也是这三组,其他模式更多是业务特殊需求才用。
record-rewrite和stride-read更贴近某些特殊业务。比如数据库更新时往往是先读出旧数据,再覆盖写入,record-rewrite模拟的就是这类行为;视频剪辑工具读取素材时经常跳跃访问大文件,stride-read能测出这种模式的效率。fwrite/fread这两组用的是标准C库的带缓冲I/O,跟write/read这种系统调用是两条路径,前者经过用户态缓冲,后者直接进入内核。对比较小的记录块,两者差异可能很明显,能帮我们理解应用层缓冲对性能的影响。
2.2 文件大小与记录大小怎么选
这是iozone使用中最重要的两个参数,选错了测出来的数据没有参考价值。
文件大小(-s)理论上要比系统内存大,最好超过2倍。原因很直接:Linux有page cache,如果测试文件只有1GB而机器内存是16GB,数据很可能一直留在缓存里,后面所有读操作都变成内存读,测出来的速度会高得离谱。要测真实磁盘性能,就得让文件大到缓存装不下,数据被迫回写磁盘、读磁盘。
记录大小(-r)模拟的是应用程序单次I/O请求的大小。OLTP数据库大多是8K到16K的小记录,视频流或大数据写入往往用1M以上的大记录。没有特殊要求时,可以跑一个范围,让iozone自动生成矩阵。
自动模式下,-n和-g控制文件大小范围,-y和-q控制记录大小范围。比如-n 512m -g 16g -y 4k -q 16m,表示文件大小从512MB测到16GB,记录大小从4KB测到16MB,每个组合都会执行一组测试。这样得到的是一个二维矩阵,能清晰看出性能随参数变化的趋势。实际跑起来这个矩阵很耗时间,文件越大、记录档位越多,耗时越长,生产环境要克制一点。
2.3 常用命令参数速查表
列几个我常用的参数:
| 参数 | 含义 | 典型用法 |
|---|---|---|
| -a | 自动模式,自动组合文件大小和记录大小 | -a |
| -i | 指定测试模式,可用多次 | -i 0 -i 1 -i 2 |
| -s | 测试文件大小 | -s 16g |
| -r | 记录大小 | -r 16k |
| -n | 自动模式最小文件大小 | -n 512m |
| -g | 自动模式最大文件大小 | -g 32g |
| -y | 自动模式最小记录大小 | -y 4k |
| -q | 自动模式最大记录大小 | -q 16m |
| -f | 测试文件路径 | -f /data/test.ioz |
| -F | 多文件路径列表,与线程数配合 | -F file1 file2 file3 |
| -t | 线程数/进程数 | -t 8 |
| -I | 使用直接I/O绕过缓存 | -I |
| -b | 测试结果写入指定二进制文件 | -b result.wks |
| -R | 生成Excel兼容格式报表 | -R |
| -C | 显示每个节点的测试信息 | -C |
| -w | 测试结束后不删除文件 | -w |
| -e | 包含fsync/flush时间 | -e |
| -v | 查看版本 | -v |
自动模式跑起来很省心,但要提醒一句:如果-g设得太大、模式选择太多,一次测试可能跑几个小时。生产环境时间宝贵,我一般限制文件大小范围,并且只选需要的模式,把自动模式当成快速摸底,不要指望一次跑完全部组合。
手动模式下,-s和-r必须显式给出,这对快速定位某个场景特别有用。比如想测某块盘在16KB记录下的随机读性能,只需跑-i 2 -s 32g -r 16k这类命令,几分钟出结果。调优过程中我基本都用手动模式,参数可控,可复现性也强。
提示:-a和-t一起用的时候,不同版本表现不一致,有些版本会报错或者结果混乱。需要多线程测试时,建议手动指定-s/-r/-i,避免自动矩阵带来的不可控。
3. 实操:一次完整的磁盘性能评测流程
3.1 测试前准备
评测磁盘性能前,先做几件事能省很多麻烦。
先确认测试目录挂载在目标磁盘上,别辛辛苦苦跑完发现测错盘了。用df -h查看挂载点和剩余空间,mount命令可以看文件系统类型和挂载参数。我习惯在目标分区单独建一个目录,比如/mnt/disk_test,避免跟业务数据混在一起。
然后确认空间足够。iozone测试文件大小建议超过内存2倍,所以文件大小加上覆盖重写需要的空间都得考虑。比如内存16G,测试文件32G,那么测试分区至少要有64G以上空闲,因为write模式和re-write模式实际会占用双份空间。这个坑我踩过好几次,文件系统写满之后测试直接失败,前面跑的数据全部作废。
测试期间尽量让磁盘空闲。在线业务在跑、后台任务在整理碎片、系统在做周期清理,这些都会干扰结果。我一般先top和iostat确认负载正常,再开始测试。如果测试的是系统盘,最好安排在业务低峰期,否则测出来的数据根本没法用于横向对比。
3.2 快速摸底:一条命令跑出基础矩阵
先跑一个自动模式的快速摸底,命令如下:
./iozone -a -g 8g -n 512m -y 4k -q 16m -i 0 -i 1 -i 2 -f /mnt/disk_test/iozone.test -b /root/iozone_result.wks这条命令的含义:自动模式,文件大小从512MB测到8GB,记录大小从4KB测到16MB,只测写、读、随机读写三种核心模式,测试文件放在指定路径,结果写入iozone_result.wks。
输出里会看到一张报表。每行对应一个文件大小和一个记录大小的组合,列方向是速度值,单位是KB/s。文件大小固定时,记录大小从小变大,速度通常会上升;小文件小记录时速度会低一些,这符合IO次数增多的客观规律。如果某个组合的数值出现断崖式下跌,说明这个尺度下有瓶颈,值得深挖。
我第一次跑自动模式时,看到满屏的数字有点懵,后来摸清规律就好了。比如某一行的顺序写是800MB/s,下一行的随机写只有150MB/s,这个差异本身就是重要信息——说明这块存储在顺序场景和随机场景表现差距大,选型时就要针对业务类型做取舍。
3.3 场景化测试:针对业务形态的精细命令
摸底之后,按业务场景细化。比如测数据库服务器磁盘,重点是随机小IO:
./iozone -i 2 -s 32g -r 16k -I -f /mnt/disk_test/rand_16k.test这里用-s 32g确保文件超过内存,-r 16k模拟数据库记录大小,-I使用直接IO绕过内存缓存,测的是磁盘真实随机读写能力。
测视频存储或备份盘,看大文件顺序吞吐:
./iozone -i 0 -i 1 -s 32g -r 1m -I -f /mnt/disk_test/seq_1m.test大记录大小1MB,直接IO,主要看顺序读写的最高吞吐。视频存储这类场景,顺序读性能往往决定并发剪辑体验,吞吐低于预期会直接影响使用。
测多客户端场景,比如NFS或并发备份,用-t指定线程数:
./iozone -i 0 -i 1 -i 2 -s 16g -r 64k -I -t 4 -F /mnt/disk_test/f1 /mnt/disk_test/f2 /mnt/disk_test/f3 /mnt/disk_test/f4这条命令用4个进程同时写4个文件,模拟并发访问。注意-F的文件数量要和-t的线程数一致,否则行为不符合预期。实际并发测试有个现象:线程数上去之后,总吞吐不一定线性增长,甚至可能下降,这跟存储控制器的并发处理能力有关,也是调优时要重点观察的指标。
3.4 结果解读与报告输出
iozone默认输出直接看就能用,但为了汇报和对比,建议输出Excel兼容格式。用-R参数或加-b参数,结果可以用Excel或LibreOffice打开。如果要做成趋势图,把wks文件导入绘图工具即可。
多跑几轮取稳定值。很多磁盘测试第一次跑会偏高,因为文件系统元数据可能还没分配完,第二次、第三次数据更接近真实。我一般跑3轮,取中间值或最小值作为结论,最大值往往有缓存或其他因素干扰。
另外建议测试结束保留一个结果文件归档,方便后续做性能趋势对比。磁盘性能下降是渐进过程,没有历史数据很难判断“变慢了多少”。我维护的服务器都会给每台建立一份iozone基线,每次出问题先跑一次,和基线对比,是健康劣化还是配置变更导致的性能变化,一眼就能看出来。
4. 常见问题与避坑指南
4.1 测试结果高到离谱?多半是缓存效应
用iozone最常见的问题是:写测试轻松跑出几GB/s,比理论带宽还高,很大概率是没绕过page cache。Linux默认策略是尽量利用内存缓存写数据,write()返回时数据可能还在内存里,系统在后台慢慢落盘。
解决手段有三个。第一,用-I参数走直接IO,数据不经过page cache,测的就是真实设备性能。第二,把测试文件设置成内存的2倍以上,缓存装不下,部分数据必然落盘。第三,测试前清一次缓存:echo 3 > /proc/sys/vm/drop_caches,再开始测。
顺序读测试相对不容易被缓存干扰,因为文件已经存在,读数据如果全在缓存里也会虚高。所以最好统一用-I测读部分,这样对比性更强。做对比验证时,所有场景要保持一致的参数,否则数据没有可比性。我这里说的对比,指的是同盘不同时间比,或者不同盘之间比,参数不一致就没有意义。
4.2 常见报错与排查手册
我整理了几个高频报错,做成一个速查表:
| 报错信息 | 常见原因 | 解决办法 |
|---|---|---|
| Permission denied | 测试目录无写权限 | 检查属主或加sudo运行 |
| Could not open file / File size too large | 空间不足或文件大小限制 | 确认剩余空间,ulimit -f放开 |
| -a与-t同时使用报错 | 版本不允许自动模式与多线程混用 | 手动指定-s、-r、-i再配-t |
| Offset too large | 32位系统大文件溢出 | 编译时加-D_LARGEFILE64_SOURCE |
| 测试中途被kill | 文件太大、写盘太慢被系统杀掉 | 减小-s或-g,拆分多轮测试 |
Permission denied这个报错最容易忽视,很多系统默认/tmp有特殊权限管理,往不能写的位置放测试文件就会这样。文件大小限制这个,很多环境里ulimit -f是unlimited,但在某些加固过的系统上会被限制,提前检查一下能省很多时间。
32位系统那个报错,现在新机器基本遇不到,但搞嵌入式或者老服务器时会踩到。解决办法是在src/current目录下先执行make clean,然后带上宏重新编译。
提示:iozone默认测试完成后会删除测试文件,若想保留文件做复测或分析,记得加-w参数。保留文件还有一个好处:可以直接对同一个文件反复跑读测试,排除创建文件带来的干扰。
4.3 实测心得与性能调优建议
跑了很多次iozone后,我有几个经验供参考。
测试前看一眼文件系统类型和挂载参数。ext4的data=ordered和xfs的默认配置,在随机写场景表现会有差别;挂载时加了barrier或sync这类选项,性能会明显下降。如果测试目的是磁盘本身,建议统一用默认挂载参数,避免文件系统因素干扰。
对SSD和HDD要区分解读结果。HDD的顺序读写在百兆到两百兆级别,随机小IO比较惨,只有几兆级别;SSD随机小IO能跑到几百兆,顺序读写如果走NVMe能到几GB/s。如果HDD随机测试数值很低,不用惊讶,这是物理规律。反过来,如果用SSD测出随机写只有几十兆,那就得怀疑固件策略或者队列深度设置有问题。
多次测试取稳定值,别拿最高值到处宣传。磁盘刚格式化完跑出来的数据往往比较好看,越往后越接近真实水平。我用iozone给几十台机器做过验收,统一的做法是跑三轮取中位数,低于厂商标称的80%就认为不合格。
测试文件尽量放在数据区的最深处。很多存储系统前端是缓存层,尾端才是真实介质,文件如果落在缓存覆盖区,测的是缓存性能。这个问题在使用存储阵列时特别明显,建议结合厂商文档确认。另外,ZFS、Btrfs这类带校验和快照的复杂文件系统,会带来额外地CPU和IO开销,测试结果比ext4偏低是正常的。
最后多说一句,iozone虽然好用,也别把它当成万能钥匙。磁盘层、文件系统层、应用层是三层不同的东西,iozone测的是文件系统层的表现。需要精确到块设备或队列深度的性能,还是得上fio这类工具。
我个人的习惯是,每台新服务器到手先跑一轮iozone归档,隔半年再跑一轮对比,磁盘状态和历史趋势一目了然。测试这东西,最重要的不是命令记得多熟,而是每次测试条件统一,数据才有可比性。这些经验都是我踩坑换来的,希望看这篇文章的人能少走点弯路。