尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
fio 3.8 磁盘性能压测完全指南:从编译安装到 IOPS/延迟分析
简介FIO是一款开源的I/O性能测试工具这一压缩包提供FIO 3.8版本的完整源码面向存储运维、性能测试工程师及底层开发者用于评估SSD、HDD、RAID等存储系统的顺序/随机读写能力、IOPS、延迟和稳定性。压缩包内共433个文件整体约872KB除C语言核心源码.c/.h外还包含fio作业配置示例、Shell/Python辅助脚本、man手册与绘图工具源码并支持ext4、XFS、Btrfs等常见文件系统及SCSI、SATA、NVMe块设备便于用户自行编译、定制测试策略并生成可视化报告。目前已有1643人学习下载在存储性能测试场景中具有不错的参考价值。借助包内的配置模板、fio2gnuplot图表生成脚本和完整文档读者可快速上手参数调优理解队列深度、块大小、缓存策略等对实际性能的影响从而用于存储设备选型、系统调优和故障排查。无论是数据中心、云计算还是嵌入式环境FIO的灵活配置都能帮助定位性能瓶颈是评估和优化存储系统的实用工具。1. 先看这 200 字fio-3.8.zip 里装的是一套磁盘性能测试工具手里的 fio-3.8.zip 解开之后就是一套 fio 3.8 的完整源码。fioFlexible I/O tester是 Linux 上最常用的存储性能压测工具你要量化一块 SSD 的随机读 IOPS、一块 HDD 的顺序写带宽、或者一台文件服务器的真实负载上限标准做法就是跑一套 fio。它和你自己写的压测脚本最大的区别在于用一条配置就能精确控制块大小、队列深度、读写比例、线程数和运行时长把「这台设备到底能扛多大压力」问到底。这篇文章适合存储选型、数据库落盘优化、给测试报告找可信数字的运维和开发。先把版本边界说清楚fio 3.8 是相对老的一个版本但它的核心参数、输出结构和后续主流版本基本一致把它吃透换到新版不会有任何重构成本。2. 把 fio-3.8.zip 变成可用的 fio编译安装与第一个基准数据拿到 zip 包之后第一件事不是跑测试而是先把源码变成可执行文件。fio 3.8 是纯 C 写的编译链很简单但它对 Linux 内核特性有依赖真正出问题的地方往往在依赖检测这一步。2.1 解压与依赖检查configure 会告诉你缺什么解压并进入目录unzip fio-3.8.zip -d /opt/ cd /opt/fio-3.8 ./configure./configure是 fio 源码里的自检脚本它会扫描当前系统里有哪些依赖可用。跑完之后要在输出里找这两行Libaio yes numa noLibaio这一行是最关键的。libaio 是 Linux 原生异步 I/O 库fio 里最常用的libaio引擎依赖它。如果这行显示no即便 fio 能编译出来你后面用--ioenginelibaio也会当场失败报错是io_setup() failed。Debian/Ubuntu 系直接装apt-get install -y gcc make libaio-dev装完重新跑./configure确认Libaio变为yes再继续。3.8 这个版本对numa的支持是可选功能没有也不影响基本压测只是少了 CPU 绑定的辅助命令不必强求。编译安装make -j$(nproc) make install-j$(nproc)是用 CPU 核数并行编译能省大半时间。make install默认把 fio 装到/usr/local/bin/fio。装完后执行fio --version能输出fio-3.8就算成了。注意如果你系统里原本有过别的版本 fio这里会覆盖成 3.8想保留多版本的话编译时用--prefix/opt/fio-3.8指定安装目录。2.2 最小压测命令10 秒跑出一组可读的数字编译通过后先用一条最小命令验证环境比直接上复杂 job 文件更容易定位问题fio --namequick-read \ --ioenginelibaio \ --rwrandread \ --bs4k \ --direct1 \ --iodepth1 \ --size1G \ --runtime10 \ --time_based \ --group_reporting逐项说明这一条命令在干什么--name是 job 的名字结果里会用它标注--ioenginelibaio指定用异步 I/O 引擎--rwrandread是随机读--bs4k是每次 I/O 的块大小模拟数据库页的粒度--direct1绕过操作系统 page cache直写设备这是压测真实磁盘性能的前提后面避坑章节会专门讲--iodepth1是一次在队列里保持的 I/O 数量--size1G是测试文件的大小--runtime10 --time_based让测试固定跑 10 秒而不是读完 1G 就停--group_reporting在多 job 时合并报告输出。跑完后终端里会出现一段对齐的表格重点看这一段read: IOPS4860, BW19.0MiB/s (19.9MB/s)(190MiB/10001msec)IOPS和BW就是你最常往外贴的两个数字。190MiB/10001msec表示在 10.001 秒内总共读了多少数据。这是整机层面的结果还没分线程。对于一台普通 SATA 盘iodepth1、bs4k随机读跑出几千 IOPS 是正常的如果跑出几十万 IOPS反而要先怀疑是不是没有绕过 page cache。2.3 理解数字的边界fio 说 19MiB/s 到底代表什么上面这个命令跑出来的数字严格说是「单线程、队列深度 1、块大小 4k、随机读、绕过缓存」这五个条件同时成立时的极限任何一个条件变了数字都会不同。iodepth1意味着每次只发一个 I/O等它完成才发下一个延迟完全暴露在总耗时里吞吐被延迟卡住。真实数据库的落盘通常是多个线程并发发 I/O 的所以单 depth 测出来的数字偏保守。fio 的哲学是不要问「这块盘多快」要问「在什么样的人工负载下多快」。所以第一条命令的意义在于验证工具链以及建立一组可复现的基线。等你拿到一台新机器第一件事就是跑这条命令存个档后续所有对比都拿它当坐标系。提示--size1G会在当前目录创建一个 1G 的测试文件。务必在目标磁盘的挂载路径下运行而不是在/root下测出了/所在盘的性能。测试临时目录用完后记得清理。3. 用 Job 文件设计一次像样的压测参数是 fio 的灵魂命令行直接拼参数的方式适合冒烟测试但真正的压测必须写成 job 文件。原因很简单可复现、可评审、可留档。你三个月后想对比两块盘的表现如果靠回忆命令行参数那数据基本是废的。3.1 为什么推荐 Job 文件而不是命令行参数Job 文件是 ini 风格[global]段放所有 job 共享的公共参数后面每个[名字]段是一个独立的压测任务。fio 有个相当实用的特性同一个 job 文件里可以定义多个段落fio 会同时启动它们相互之间形成真实的并发压力。用 job 文件的第二个理由是参数分组。--bs4k在命令行里只能作用于当前这一个 job在 job 文件里你可以把公共参数放在[global]然后让[db-sim-read]和[db-sim-write]分别覆盖各自要差异化的字段。后续改参数只需要改一行不用翻 shell 历史。另外job 文件天然适合放进 Git。每次压测的磁盘型号、固件版本、参数组合、结果 JSON 放同一个目录提交就是一份完整的存储测试记录。这一点对要出正式测试报告的团队尤其重要。3.2 一份模拟数据库负载的完整 Job 文件下面是一份我常用的模板用来模拟数据库日志盘与数据盘的混合负载[global] ioenginelibaio direct1 group_reporting time_based runtime60 size4G [db-log-write] rwwrite bs8k iodepth8 numjobs1 [db-data-read] rwrandread bs8k iodepth16 numjobs4 [db-data-write] rwrandwrite bs8k iodepth16 numjobs4这份 job 文件同时跑三个任务db-log-write做顺序写模拟 redo log 的追加写db-data-read和db-data-write做随机读写模拟数据文件的索引扫描与数据更新。runtime60让整个压测持续 60 秒size4G限定每个 job 的文件大小。逻辑说明数据库负载最典型的特点是读写混合且并发高单一顺序读或单一随机写都无法暴露存储设备在压力叠加时的真实表现。numjobs4启动 4 个进程同时发 I/O每个进程各自的iodepth16算下来数据盘方向的实际并发是 4×1664。这个并发水平对 SSD 是中等强度对 HDD 已经接近饱和能看出设备在不同并发下的拐点。3.3 关键参数选型bs、iodepth、numjobs、direct 如何组合bs块大小直接对应你的业务 I/O 模型。数据库页常见 8k日志通常走 512B 或 4k视频文件通常是 1M 起。fio 里--bs8k是固定块--bs4k-16k是在区间内随机选择块大小用来模拟更复杂的分层存储负载。块大小会显著影响 IOPS 与带宽的关系块越小越考验 IOPS块越大越依赖带宽。iodepth是 fio 压测里最有玄学味道的参数。它不是线程数而是「在异步 I/O 提交队列里同时挂起的请求数」。libaio引擎下真正决定压力的公式是numjobs × iodepth。我在实际压测中一般从 1、4、8、16、32 五档开始扫看带宽和延迟的拐点。如果在深层级下 IOPS 不再涨而延迟开始飙升说明设备或控制器已经到瓶颈了。direct1是压测存储设备而非文件系统的前提。它用了O_DIRECT标志绕过 page cache让 I/O 直达设备层。有个附加约束O_DIRECT要求块大小是底层文件系统逻辑块大小的整数倍如果用--bs3k之类不合法的块大小fio 会直接报Invalid argument。这一点在踩坑章节还会再提。还有个容易被忽略的组合是rw与rwmixread。想在同一个 job 里做混合读写用rwrw再配合rwmixread80表示读占 80%。但要注意混合模式下 fio 的读写共用一个iodepth队列实际读并发会被写挤掉。要精细控制读写各自的并发就得像上面那份 job 文件一样拆成两个独立 job。4. 看懂 fio 的输出带宽、IOPS、延迟到底信谁fio 的输出信息量很大但结构其实很固定。新手最容易犯的错是只盯着最顶上的IOPS看把中间一大段延迟分布当成噪音。真正能帮你判断设备健康度、定位瓶颈的恰恰是那些被跳过的部分。4.1 fio 输出的三段结构job 头、统计块、延迟分布一次跑完后的输出从上到下是三个层次。第一层是 job 头说明每个测试段的配置摘要比如rwrandread, bs(R) 4096B-4096B, ioenginelibaio, iodepth1它的作用是让你确认实际生效的参数和你写的一致防止手滑写错。第二层是统计块包括 IOPS、带宽、总数据量、运行时长以及 CPU 占用。第三层是延迟分布核心是clat和lat两组字段。典型的延迟部分长这样clat percentiles (usec): | 1.00th[ 212], 5.00th[ 224], 10.00th[ 229], | 50.00th[ 262], 95.00th[ 347], 99.00th[ 456], | 99.50th[ 529], 99.90th[ 780], 99.95th[ 906],clat是完成延迟completion latency从 I/O 提交到完成的时间是衡量存储设备延迟最直接的指标。lat则是从 fio 发起 I/O 到完成的总延迟比clat多了 fio 自身在用户态的排队时间。iodepth1时两者几乎一样iodepth32时lat会比clat大不少因为请求在 fio 内部排队了。看延迟分布时我习惯先看p50再看p99.9。两者接近说明设备延迟稳定两者差距超过一个数量级说明有严重的尾延迟大概率是垃圾回收、写缓存刷盘或者拥塞导致的卡顿。数据库场景里p99比平均值重要得多因为慢查询往往由最慢的那次 I/O 决定。4.2 用 JSON 输出对接监控与后续处理终端里的表格适合人看但你要把它写进报告、喂给监控系统、或者做多轮对比就得用 JSONfio db-sim.fio \ --output-formatjson \ --outputresult-20250601.jsonfio 3.8 的 JSON 结构里核心数据在jobs数组里。每个 job 对象下有read和write两个子对象里面分别有iops、bw_bytes、clat_ns、lat_ns字段。用jq提取特定指标jq .jobs[0].read.iops result-20250601.json jq .jobs[0].read.clat_ns.percentile[99.000000] result-20250601.json第一条是第一个 job 的读 IOPS第二条是读完成延迟的 99 分位单位是纳秒除以 1000 就是微秒。注意 3.8 版本里 percentiles 的 key 是字符串形式的百分数所以要用双引号包住。不同小版本的 JSON 字段结构略有出入如果你发现提取结果为空最直接的办法是jq .jobs[0].read | keys先看有哪些字段名。4.3 从数字反推存储类型特征SSD、HDD、网络盘的指纹跑多了之后你会形成一套直觉判断。HDD 的顺序读带宽能做到 150~260MiB/s但iodepth1的随机读 IOPS 往往只有一两百SSD 的随机读 IOPS 随iodepth提升呈接近线性的增长直到控制器饱和网络盘比如 NFS 或 iSCSI 挂载最明显的指纹是延迟分布极不稳定p99经常是p50的几十倍。这套判断在验证测试环境是否正常时特别有用。比如你拿一台新 SSD 测randread --iodepth32IOPS 应该轻松上万如果跑出来只有几千且clat的p99异常大先别急着怀疑盘查一下是不是跑在虚拟机里或者挂载点经过了网络文件系统。有一次我拿到一台「高性能服务器」怎么测带宽都只有 80MiB/s最后cat /proc/mounts才发现/data是远程挂载。fio 的数字从来不说谎但它默认不会主动告诉你测试对象到底是什么。提示fio 3.8 的默认输出单位是二进制前缀MiB/s而不是MB/s。两者相差约 4.8%对外汇报时务必统一口径否则报告里的数字会自己打架。5. 避坑fio 压测最容易在哪些地方翻车fio 本身很稳定翻车基本都是环境问题或参数组合问题。下面这五条是我在多个项目里反复踩过的每一条都是「现象 → 原因 → 解决」的结构可以直接对照排查。5.1 读性能高得反常一块破盘跑出几 GB/s现象--rwread或--rwrandread测试结果里带宽高达数 GB/s远超这块盘的能力而且runtime期间 CPU 占用还很低。原因--direct默认是 0意味着读操作先落到系统 page cache。第一次读之后数据就留在内存里了后续的重复读全是缓存命中测的是内存带宽不是你手上的盘。这是 fio 新手最容易踩的坑没有之一。解决所有面向磁盘本体的压测都加--direct1或者 job 文件里的[global]段写direct1。加了之后依然异常的检查测试文件是否落在了 tmpfs运行df -h看挂载点。tmpfs 本身就是内存盘测它等于测内存。5.2 测试提前结束明明设了runtime60却 12 秒就停了现象命令里写明了--runtime60但实际运行时间不到设定的值输出里总数据量也远小于预期。原因--runtime只有在加上--time_based时才作为强制终止条件。如果不加fio 的终止条件是size范围内的数据被全部访问完runtime只是上限。随机读模式下I/O 覆盖完整个size空间之后自然退出用不满 60 秒。解决加上--time_based。它的含义是「读完一遍再从头继续读直到时间耗尽」。另一个方案是把--size调大比如--size20G但这样需要更多的磁盘空间不够优雅。我一般固定用time_based。5.3 用libaio报错或者压根用不了现象--ioenginelibaio运行时提示io_setup() failed: Cannot allocate memory或者./configure输出里Libaio no。原因libaio-dev 没有安装或者内核的aio-max-nr限制太小。前者是依赖缺失后者是系统级限制——fio 每个iodepth都会消耗 aio 上下文大量 job 同时跑时会触顶。解决先确认依赖Debian/Ubuntu 装libaio-devCentOS/RHEL 装libaio-devel重跑./configure --disable-optimizations再编译。如果依赖没问题但运行时仍报Cannot allocate memory临时调高系统限制sysctl -w fs.aio-max-nr1048576注意fs.aio-max-nr是内核参数重启后失效。要持久化就写进/etc/sysctl.conf。另外fio 3.8 这个年代还没有io_uring引擎那是 3.9 之后才加入的用 3.8 的时候别写ioengineio_uring。5.4 新盘第一次测就差到离谱隔一段时间又变好现象一块全新的 SSD 做随机写刚开始 IOPS 很低、延迟巨大跑几分钟后数字逐渐变好最终稳定在一个相对高的水平。两块同型号盘一个先做了几轮写测试另一个全新跑出来的成绩不一致。原因SSD 存在写放大与垃圾回收的冷启动过程。全新的盘没有有效数据需要回收随机写要同时更新映射表和数据块产生大量额外写随着测试进行盘内的数据布局被打乱FTL 的垃圾回收开始介入并逐渐形成稳态。这是 SSD 硬件特性不是 fio 配置的错。解决测试目标如果是「稳定态性能」先做一轮预处理常见的做法是先跑一次满盘顺序写然后等 2~3 分钟让盘做后台垃圾回收再开始正式压测。fio 3.8 没有--precondition参数但可以用一条单独的命令完成fio --nameprecond \ --ioenginelibaio \ --rwwrite \ --bs1M \ --direct1 \ --size100% \ --loops2--size100%会把整块盘写完一遍。正式测试前跑这一条能显著减少盘状态对结果的影响。5.5 多 job 压测时延迟剧烈抖动IOPS 却不涨反跌现象numjobs从 8 加到 64IOPS 不仅没有按比例提升反而下降延迟的p99从几百微秒飙到几千。原因CPU 核数不够了。每个numjobs都是一个独立进程64 个进程在 8 核机器上跑光线程切换和锁竞争就消耗了大量 CPUI/O 请求在 fio 用户态排队的时间变得不可忽略lat虚高。解决先看测试输出里的cpu usr/sys字段如果 sys 超过 30% 甚至 50%CPU 已经是瓶颈。把numjobs降到 CPU 核数附近通常是核数的一半到一倍之间再对比 IOPS。另一个可行手段是用taskset把不同 job 绑到指定核减少调度抖动taskset -c 0-3 fio db-sim.fio这个方法对网络存储的压测尤其有效它能把中断和 fio 进程分开延迟波动明显变小。fio 3.8 也支持在 job 文件里写cpus_allowed0-3效果等价但需要一点点排查经验才知道什么时候该绑。6. 把 fio 用进日常流水线验证数据完整性与自动化提取指标前面的内容解决了「怎么跑、怎么读、怎么排错」最后这一步是让 fio 真正融入你的日常工作除了性能数字你还要知道存储有没有悄悄写错数据以及当测试变成每月例行任务时怎么让机器自动帮你把结果聚合成一张可比对的表。6.1 用 verify 模式确认存储没写错位性能达标但数据损坏是最隐蔽的存储故障。fio 内置了数据校验能力可以在写测试时给每个块算一个校验和写完后自动读回比对。命令如下fio --nameverify-test \ --ioenginelibaio \ --rwwrite \ --bs8k \ --direct1 \ --size1G \ --verifycrc32c \ --verify_fatal1--verifycrc32c为每个数据块附加 CRC32C 校验值--verify_fatal1表示一旦发现校验失败立即终止并返回非零退出码方便脚本捕获。这块盘如果在读写过程中丢位、跳写或单元损坏fio 会明确告诉你哪个字节对不上。代价是大概 3%~5% 的额外写放大作为设备验收场景完全可以接受。这套校验逻辑对应的是存储硬件层面的数据完整性和上面性能压测是互补的两件事。6.2 用 JSON 输出做多轮对比把决策交给数字我自己的例行做法是同一组参数跑遍不同iodepth把结果存成一组 JSON再逐档提取关键指标。写成脚本就是for depth in 1 4 8 16 32; do fio --named$depth \ --ioenginelibaio \ --rwrandread \ --bs4k \ --direct1 \ --iodepth$depth \ --size1G \ --runtime15 \ --time_based \ --output-formatjson \ --outputd$depth.json done for depth in 1 4 8 16 32; do printf iodepth%s $depth jq -r IOPS\(.jobs[0].read.iops) p99\(.jobs[0].read.clat_ns.percentile[99.000000] / 1000)us d$depth.json done第二段循环的输出是一行一个 depth直接把五档的结果打印成可横向对比的文本。这里clat_ns是纳秒除以 1000 转成微秒。打印出来的表会清楚地展示一个趋势IOPS 先随 depth 上升到某个深度后增长放缓甚至回落同时 p99 延迟开始陡增——那个拐点就是这台设备最合理的队列深度配置区间。数据库把innodb_io_capacity配在那个区间附近往往比套用默认值有更稳定的表现。这套方法的好处是它让存储验证变成一条可重复的流水线跑测试用 job 文件、存结果用 JSON、看趋势用 jq。我个人的习惯是让 CI 每天深夜跑一轮 60 秒的冒烟压测发现 P99 延迟连续两天抬升超过 20% 就自动告警很多盘在真正坏掉之前一到两周就能露出这种端倪。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

基于Spring Boot的亚冬会门票销售系统设计与实现

基于Spring Boot的亚冬会门票销售系统设计与实现

1. 项目概览与技术选型思路做毕设选题的时候,很多人第一反应就是“找个能跑通、能演示、好答辩的”,这话没毛病,但实际操作起来容易两个极端:要么选了个超级管理系统,增删改查四件套,做完自己都觉得虚&…

📅 2026/10/13 19:58:38
tlroadmap 指南:Team Lead 能力路线图的结构、使用方法与知识库组织方式

tlroadmap 指南:Team Lead 能力路线图的结构、使用方法与知识库组织方式

文档知识库 【免费下载链接】tlroadmap Тимлид – это ❄️, потому что в каждой компании он уникален и неповторим. 项目地址: https://gitcode.com/gh_mirrors/tl/tlroadmap 点击查看 免费下载 本文基…

📅 2026/10/13 19:53:34
JavaSE学习路线详解:从零基础到核心知识全攻略

JavaSE学习路线详解:从零基础到核心知识全攻略

如果你正处于“准备学Java,收藏了一堆视频和路线图,却不知道第一脚该往哪迈”的状态,那这篇文章就是写给你看的。JavaSE学习这个阶段,是所有Java技术栈的起点——后端开发、Android开发、大数据处理,底层核心都建立在它…

📅 2026/10/13 19:53:34
MORE NEWS

更多资讯

📰

D-S证据理论多传感器融合MATLAB实现:从BPA构造到冲突处理与决策

简介:这份资源面向信号处理、目标检测与多传感器融合方向的学习者与工程实践者,提供基于D-S证据理论的多传感器信息融合MATLAB实现方案,帮助解决多源观测数据存在冲突、不确定与不完整时的统一处理与决策问题。压缩包共3个文件,均…

📰

Python接口自动化Token全攻略:从提取到封装与自动刷新

做接口自动化测试这几年,我感触最深的一件事就是:几乎所有需要登录态的业务接口,都绕不开Token这个话题。新手写脚本时,第一步往往是和登录接口较劲,第二步就是和Token较劲——Token拿到了不知道怎么存,存好…

📰

基于Spring Boot的体育赛事视频管理系统毕业设计全解析

1. 这类系统在毕业设计中的定位:先想清楚要做什么体育赛事视频管理系统,光看这个名字就知道,它天然具备一个毕设选题该有的所有优点:领域直观、功能边界清晰、用户角色分明、技术栈覆盖面广。从我们做过的项目经验来看&#xff0c…

📰

从802.11到Wi-Fi 7:无线局域网核心概念与现场排障实践

简介:《无线局域网基本概念》PPT是一份面向计算机网络初学者、通信专业学生及无线网络部署人员的入门文档,系统梳理了Wi-Fi与WPAN两大无线网络体系。全包共1个PPT文件,压缩包大小724KB,内容按章节组织,便于教师授课或自…

📰

自建跨平台进程与计划任务管理器实战指南

1. 为什么我要自建一个进程和计划任务管理器说到进程和计划任务管理器,我最初的需求其实非常简单:想在一个页面里同时看清所有服务器的进程状态和定时任务执行情况。这个念头源于一次凌晨的故障排查——某个备份脚本没有按时跑,我先后打开了系…

📰

BL0940电能计量芯片设计实战:从硬件采样到量产校准

简介:面向硬件与嵌入式开发者的BL0940电能计量专用电路设计资料,涵盖芯片外围电路、代码实现与完整工程文件。资料围绕BL0940在智能电网、智能家居、工业自动化等场景的高精度电能测量需求,重点讲解模拟前端信号调理、数字信号处理及RS485/Mo…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬