
前阵子帮某团队优化一套日志采集系统的存储测试结果单看峰值很不错可一上业务就延迟飙升查了半天问题出在最基础的IO特征没对齐。这类事在存储运维里太常见了很多人压测只跑一个fio默认参数拿到的数字除了发个报告什么也说明不了。Storage Performance这个领域真正值钱的不是峰值IOPS而是搞清楚IO characteristics——你的业务到底在制造什么样的IO模式存储在这类模式下能跑到什么水平以及哪些参数是你可以调的。这篇文章我从实际踩坑的视角把存储性能测试这事拆开讲明白IOPS、带宽、延迟之间的关系随机和顺序读写为什么差别巨大队列深度怎么影响结果压测工具怎么选怎么配实测数据怎么解读常见的坑怎么排查。适合刚接触存储性能评估的运维、DBA和平台工程师也适合那些正准备给新系统做存储选型但不确定该怎么设计测试方案的朋友。1. 先把业务场景翻译成IO特征指标1.1 认识三个基本指标IOPS、带宽、延迟存储性能评估绕不开三个物理量IOPS、带宽和延迟。先说IOPS全称是Input/Output Operations Per Second每秒能完成的读写操作次数。带宽也叫吞吐量是每秒能传输的数据量常用MB/s表示。延迟则是单个IO从发出到完成的时间常用毫秒或微秒计。这三者不是独立的它们的关系就像货运车队。IOPS是每秒能发多少辆车带宽是所有这些车加起来能运多少吨货延迟则是每辆车从装货到卸货返回用了多长时间。如果每辆车只装一箱货4KB小块IO那吞吐主要靠发车频率即IOPS如果每辆车装满满一集装箱1MB大块IO吞吐则取决于单次搬运能力也就是带宽。所以测试时不能只报一个数必须把块大小一起报出来否则“IOPS 10万”毫无意义——10万次4KB随机读和10万次1MB顺序读对存储系统的压力完全不是一个量级。延迟方面有个容易忽略的点平均延迟看着正常不代表系统真的健康。存储控制器内部一旦开始垃圾回收、磨损均衡、快照合并等后台操作某些IO会被拖到几十甚至上百毫秒产生“尾部延迟”。这些零星的突发延迟如果落在数据库事务提交路径上SQL整体耗时会被显著拉长业务侧感知就是“时不时卡一下”。所以后面我测延迟都会同时记录P50、P99和P99.9只报平均值等于没说。1.2 四种IO形态顺序读、顺序写、随机读、随机写在压测工具里读写模式被抽象为四类顺序读read、顺序写write、随机读randread、随机写randwrite再加上它们的组合rw混合模式。顺序IO的特点是访问地址连续底层介质可以预取、可以高效合并随机IO的地址跳来跳去对机械盘意味着寻道对闪存意味着更多的地址映射开销和搬移操作。真实业务里这些模式都能找到对应场景。顺序写最典型的是日志写入和视频流录入数据一条条追加到文件末尾顺序读对应数据仓库的全表扫描、视频回放、冷数据备份恢复随机读是OLTP在线事务处理的主旋律比如电商系统的订单查询每次只取几条记录随机写则出现在数据库的Redo Log之外的更新操作、搜索引擎索引更新、消息队列的持久化落盘等场景。这四类IO里随机写通常是最难啃的骨头。拿机械硬盘举例顺序写可以做到接近200MB/s随机写4KB小块却可能只有几MB/s差距几十倍。即使是NVMe固态盘随机写也会因为闪存必须按块擦除的特性需要做大量后台搬移性能受写放大影响明显。所以评估一套存储系统我会先看它的随机写能力那是整个系统设计水平的试金石。1.3 队列深度和并发数决定压力的“形状”压测时有两个参数经常被混为一谈iodepth和numjobs。iodepth是单个压测进程提交给存储的IO请求队列深度意思是这个进程最多同时有多少个IO在飞行中不需要等前一个完成再发下一个numjobs则是并发进程数。两者都会增加系统的总并发IO数量但路径不同前者考验存储设备的队列处理能力后者还涉及操作系统调度和多进程/多线程开销。可以用餐厅来类比排队点餐的深度相当于队列深度能同时排队的队伍数量相当于并发数。队列深一点厨房可以同时备好几份菜吞吐上去了但每个人等餐的时间也会增加延迟自然升高。所以压测时队列深度不是越大越好得看业务真实能做到多少并发。数据库通常一条SQL请求对应一定数量的并发IO不会无限增加队列而备份工具、大数据批量任务则可能把队列拉得很高。我实际测试时会固定numjobs1单独调整iodepth这样能把队列深度对IOPS和延迟的影响曲线测出来然后再固定某个合理iodepth增加numjobs观察多并发下的叠加压力。两轮测完能比较清楚地看出这套存储的饱和点和最佳工作区间。1.4 平均延迟不够要看尾部时延P99一次完整的压测输出里工具会给出min延迟、平均延迟、p50、p95、p99和max等多个统计值。很多人只看平均延迟这是最容易踩的坑。平均延迟被大量快速IO平均掉了一个1000毫秒的超长延迟在1万个1毫秒的IO里只贡献不到0.1毫秒的增量肉眼完全看不出异常但业务那边那个慢请求已经拖垮了一个事务。尾部延迟在存储系统里特别重要因为上游业务往往有超时设置。比如支付系统要求下单接口P99小于200毫秒存储层若偶尔出现一次500毫秒的延迟就会导致少量请求超时失败用户体验是“偶尔失败一次但查不到规律”。压测时我会重点观察P99和P99.9在长时间运行时是否稳定凡是P99曲线出现周期性跳变大概率是存储内部有后台任务在周期性抢占资源这点在后面的排查章节会细说。2. 压测前的方案设计业务模型决定测试矩阵2.1 先问三个问题业务类型、负载模型、目标指标拿到一套存储设备或一个压测任务我的习惯是先问三个问题而不是立刻开跑工具。第一个问题这套存储要承载什么业务是数据库重事务负载还是大数据分析扫描或者是日志流水写入不同业务对应的IO形态完全不同。第二个问题业务的读写比例和块大小大致是多少这个可以通过观察现有系统的IO统计拿到比如Linux下的iostat的rrqm/s、wrqm/s、avgqu-sz和平均请求大小都能给出粗略画像。第三个问题性能目标是什么是追求高吞吐还是低延迟还是两者兼顾目标不同测试标准也不同。这三个问题背后是同一个逻辑压测不是跑出一个理论峰值而是回答“这套存储能不能撑住我的业务”。如果业务是订单交易我压测时就会用4KB随机读写、读写比例7:3、队列深度控制在8-16如果业务是日志归档那测试应该偏顺序写、块大小64KB-256KB、关注持续带宽和长时间稳定性。目标定错了测出来的数字再好看也没用。2.2 测试矩阵的设计思路方案落地时我习惯先做一张测试矩阵把不同场景拆成组合每个组合单独记录结果。矩阵列通常包含压测场景、块大小、读写模式、读写比例、队列深度、运行时长、关注指标。行则按业务需求划分。举个例子一套面向数据库场景的SSD存储测试矩阵可以这样设计压测场景块大小读写模式读写比例队列深度运行时长关注指标在线交易IOPS4KB随机混合70/301630分钟IOPS、P99延迟批量导出带宽1MB顺序读100/03230分钟带宽、平均延迟日志落盘64KB顺序写0/100830分钟带宽、P99延迟峰值冲击4KB随机写0/10025610分钟IOPS、最大延迟每一种组合都对应一个生产上的问题“这个场景下单盘能扛多少并发”、“这个场景下两块盘是否线性扩展”或者“这个缓存参数对该场景是否有明显影响”。矩阵做好了后面测试才有章法否则就是拿同一组参数反复跑测完还是一头雾水。2.3 工具选型和环境准备要点Linux环境下fio是我用得最多的压测工具没有之一。它几乎能模拟所有IO形态且参数粒度细能够精确控制队列深度、块大小、ioengine、直接IO模式等。另一个常用工具是vdbench适合做更复杂的存储虚拟化和多协议场景模拟但学习成本高一些日常fio足够。Windows平台则用微软的diskspd参数风格类似。环境准备有几个容易被忽略的细节。第一文件系统要对齐SSD和RAID卡的strip大小如果和分区起始偏移不对齐性能会打折扣通常分区工具默认对齐到1MB即可。第二测试时用direct1绕过操作系统页缓存否则数据先落在内存里工具测出来的是内存和缓存的速度不是存储的真实能力。第三测试文件建议使用单个大文件如64GB以上避免触碰到文件系统元数据频繁更新的干扰也避免存储缓存覆盖全部测试区域导致结果虚高。2.4 fio配置模板与关键参数解析下面是我常用的一套fio配置模板用于4KB随机混合读写测试压测目标是评估一块SSD在数据库负载下的表现。[global] ioenginelibaio direct1 rwrandrw rwmixread70 bs4k iodepth16 numjobs1 runtime600 time_based group_reporting filename/data/fio_test.dat size64G [test]关键参数逐个说清楚。ioenginelibaio表示使用Linux异步IO接口这类接口才是真实业务里数据库和高性能应用常用的路径direct1绕过页缓存直接对磁盘发IO确保测的是存储真实能力rwrandrw表示随机混合读写rwmixread70表示读占70%、写占30%bs4k是块大小iodepth16是队列深度runtime600是运行600秒time_based表示即使提前写完文件也继续跑。还有个容易被忽略的参数group_reporting它让多个job的统计结果合并汇总否则numjobs大于1时结果会散成一堆读数非常痛苦。size64G是测试文件大小建议至少是物理内存的一倍以上避免文件全部被缓存也确保测试覆盖足够大的存储空间来体现稳态性能。3. 完整实测流程从单点到IO特征画像3.1 第一步定基线——单盘随机写实测真正动手的时候我一般先跑一轮简单的小块随机写给整体性能定个基调。比如对一块企业级SATA SSD执行如下命令fio --namerandwrite_test \ --ioenginelibaio \ --direct1 \ --rwrandwrite \ --bs4k \ --iodepth32 \ --size64G \ --time_based \ --runtime300 \ --group_reporting跑完看结果重点关注几个字段IOPS表示每秒IO次数BW表示带宽KB/sclat是完成延迟的统计分布包括p50、p99、p99.9max是最大延迟。一个典型结果可能长这样write: IOPS42.1k, BW164MiB/s clat percentiles (usec): | 1.00th[ 122], 50.00th[ 195], 99.00th[ 417], 99.90th[ 1413]第一眼我会看IOPS和P99延迟是否在同一个小数量级——如果P99时延是平均时延的几倍甚至十几倍说明系统尾延迟控制得不好。再看max那一行的最大值通常比P99.9大不少这部分通常是偶发的后台操作可以记录但不能作为主要判断依据。单盘基线的意义不在于数字高低而在于给后续所有测试提供一个参照。多盘RAID的性能、控制器缓存开与关的影响、不同队列深度下的表现都要拿这个基线做对比才能看出改动到底有没有效果。3.2 第二步块大小扫描——找到性能转折点同一套存储块大小从4KB扫到1MB性能表现会在某个尺寸附近出现明显转折。这背后是硬件特性的分界小块的瓶颈在IOPS上限和地址映射开销大块的瓶颈在介质带宽和控制器处理能力。我常用的做法是写一段循环脚本让fio依次跑bs4k、8k、16k、32k、64k、128k、256k、512k、1024k每次固定队列深度记录IOPS和带宽。然后画一张表块大小IOPS带宽MB/s平均延迟ms4K420001640.198K380002970.2116K320005000.2532K240007500.3064K150009400.40128K850010600.55注意看64K到128K之间带宽增长明显放缓甚至持平说明介质带宽接近上限而4K到8K带宽翻倍但IOPS下降说明IOPS逐渐不再是瓶颈。这条曲线对应用层的意义是如果你的业务平均请求大小是8K那带宽和IOPS的平衡点正好在比较理想的位置如果业务大量产生1MB大块请求那更高队列深度带来的收益就会很有限。还有一类重要的转折是随机写下的“写放大”效应。部分固态盘在随机写跨闪存页边界时会触发内部读改写实际物理写入量大于逻辑写入量表现为随机写的带宽远低于同块大小的顺序写。扫描测试时可以加一组顺序写对照如果两者差距超过3倍就要特别留意。3.3 第三步队列深度阶梯——找到最佳工作点固定块大小改变队列深度从1到256是压测里最有价值的一步。这能看见IOPS和延迟如何随着压力上升而变化并找到这套存储的饱和点。举个例子同一块NVMe盘4K随机读在不同iodepth下的表现可能如下队列深度IOPSk平均延迟usP99.9延迟us17.8128220425.3158410841.01957303276.8390180012888.214506800队列深度从1提到8IOPS翻了5倍多延迟只是小幅增加这是增益区间。到32再到128IOPS继续涨但幅度很小延迟却翻了近十倍这是典型的“收益递减区”。生产环境的使用建议是如果业务对延迟敏感把并发控制在8左右如果追求吞吐且能容忍更高延迟32是可接受的上限继续压到128以上对业务没什么好处只会把存储打到高延迟区。这块的经验是不同厂商不同型号的盘拐点位置差异很大不要拿别人的结论套自己的设备必须自己扫一遍。3.4 第四步混合读写模拟——贴近真实负载纯读和纯写能看清存储单方面的能力上限但生产环境里读写通常是混在一起的。混合读写对存储控制器的挑战更大因为读和写会争抢内部资源也有一些设备会做读写分离优化实际混合表现和纯测试的结果没有直接关系。混合测试的关键参数是rwmixread和rwmixwrite用来指定读写比例。接口型业务偏读常见70/30日志型业务偏写常见20/80。如果业务模型不确定就做一组梯度100/0、80/20、60/40、40/60、20/80、0/100用折线图看性能如何随读写比例变化。有个容易被忽略的问题混合读写时读延迟会受到并发写的影响出现周期性抖动。这在很多系统上都会发生比如固态盘垃圾回收期间写操作占用的带宽明显上升瞬间拖慢读请求。压测时我会额外记录读请求的P99延迟而不是只看整体混合结果否则会把读端的问题掩盖在混合平均值里。4. 实测中的典型异常与排查思路4.1 尾延迟周期抬头后台回收与节流压测时最让人头疼的现象是延迟曲线周期性升高二十秒正常忽然一秒内P99翻十倍然后又恢复。这种周期性往往不是网络或接口卡问题而是存储设备内部的后台任务在“打断”正常服务。固态盘的垃圾回收是最常见的原因。块必须先擦除才能写入后台回收进程在空闲时把数据搬来搬去一旦你的写入压力过大回收就跟不上控制器会暂停一部分IO来处理于是出现周期性延迟尖峰。机械硬盘阵列也类似一致性校验、磁盘巡检、快照后台同步都会造成抖动。排查方法分两步。第一步把压测时长拉长到1小时以上记录P99的时序曲线如果锯齿波周期稳定基本可以认定是后台任务调度第二步通过设备的管理接口关掉或错峰安排后台扫描任务重新测试如果抖动消失问题定位就完成了。4.2 结果忽高忽低缓存、直写和冷热数据的影响同样的命令早上跑一遍和下午跑一遍IOPS差两三倍这事我碰过不止一次。多数原因是缓存和冷热数据在作怪。现代存储设备内部都有DRAM缓存和闪存加速层。测试文件如果小于缓存容量第一次写完的文件数据可能全部留在缓存里第二遍跑读就是纯缓存速度自然“性能爆表”。想要规避第一是用direct1绕过操作系统缓存第二是确保测试文件明显大于设备内部缓存。很多存储厂商会在官网标注缓存大小测试之前查一下把文件设到缓存的3倍以上数据才可信。还有一个冷数据导致的迷惑现象测试刚开始速度极快跑几十秒后断崖式下跌。这是因为初始阶段设备在向闲置闪存块直接写入不需要任何搬移持续写了一会儿闪存可用块减少后台回收开始介入性能逐渐回落到稳态。这就是为什么测试至少要跑十几分钟而不是看头三十秒。4.3 数字和厂商标称对不上接口、队列与方法差异经常有人拿着买盘时的说明书来问我厂家写的顺序读3500MB/s为什么我测出来只有2200MB/s差异通常出在三个地方。第一是接口链路和驱动。PCIe插槽带宽、NVMe驱动是否开启多队列、BIOS里PCIe链路是否降速跑都能造成带宽差异。第二是队列深度和并发数。厂商测试往往用多队列、深并发压出最高值现场单线程浅队列自然达不到。第三是测试工具的校准差异有的工具默认开启页缓存结果包含了内存加速有的工具则统计口径不一样导致看起来差一截。现场排查的顺序是先用lspci确认链路速率再看系统日志里有没有掉链路和超时事件接着对比厂商给的测试条件和你的条件缺什么补什么。说句实在话接近标称值的80%以上且稳定这设备在现实环境里已经算正常发挥。4.4 现场排障速查表实在没头绪的时候对照这张表找方向。现象可能原因排查手段IOPS上不去但CPU没跑满队列深度太小、块大小和业务不符逐级加大iodepth观察拐点延迟周期性跳变后台回收/巡检/一致性校验拉长测试时间观察P99时序随机关卡在极低水平受限于锁或页竞争单队列能力差多numjobs测试排除单进程瓶颈带宽测试远低于标称PCIe降速、驱动队列未开启查lspci、驱动参数、固件版本多盘无扩展性RAID条带过小或热点集中在单盘观察单盘统计调整条带大小测试文件超过缓存后暴跌设备缓存太小或写放大严重加大文件尺寸重测确认稳态值每次压测结束我会把这些现象和参数变化整理成一份记录下一次再遇到类似问题直接翻记录比对比临时查手册快得多。5. 把IO特征用回到生产设计里5.1 从业务负载描述到存储选型参数做完一轮IO特征测试最终目的是指导生产设计。很多选型讨论都在比纸面参数但真正落到实处的是把你业务产生的负载描述成一串可度量的特征参数实际块大小分布是什么、读写比例多少、并发压力高还是低、可容忍的P99延迟是多少毫秒。举例来说某生产数据库业务的负载特征是“4KB随机读写为主读写比7:3单实例并发IO在20左右业务要求P99延迟低于5毫秒”。拿着这个描述去对照测试结果如果某块盘在iodepth16的随机混合测试里P99是3毫秒那它留有余量可用如果P99已经到8毫秒那要么换更高规格的设备要么在架构上做读写分离把压力降下来。这里面有个原则按P99选型而不是按平均延迟选型。平均延迟再好看救不了偶尔的慢查询。5.2 性能到容量的粗略换算性能测试还能帮你算数量不只是选型号。假设业务峰值需要2万随机写IOPS单盘实测稳态随机写5000 IOPS理论算下来至少4块盘。但我会在此基础上再乘1.3到1.5的冗余系数因为业务峰值不是持续均匀的存储设备也有寿命和故障率留足余量才不至于一有波动整个系统就扛不住。这个逻辑也适用于容量规划。如果按容量算出配10块盘但按性能算出至少要16块那就按16块来配。大多数系统从性能角度配的盘都比容量需求多反过来情况也有但相对少见。测试数据这时候就是说服决策层加预算的最有力证据。5.3 业务侧联动优化才是终局存储性能不只是存储设备的事很多时候改业务侧的IO模式比换设备还见效。压测过程中你会发现有些看似存储的问题其实根源在应用的IO模型太糟糕比如把大量小写操作直接写在每行关键路径上而不是先合并到缓冲区批量落盘比如每次都打开关闭文件而不是复用句柄比如日志直接同步写而没有异步批处理。实践中最有效的组合是“业务层批量 存储层对齐”。应用层把随机小块合并成较连续的中等块比如把8个4KB小IO合并成32KB存储层性能往往就能提升一个台阶因为减少了IOPS压力同时带宽也能更充分利用。做完这类优化后再用之前的测试矩阵跑一遍对比结果你会看到IO特征曲线整体右移系统容量和性能余量都变大了。最后分享一个我常用的习惯每隔一段时间就给线上系统做一次IO场景快照测试。不用环境全停工具限制好文件大小和运行时长挑低峰期跑记录下IOPS和延迟曲线的变化。设备是有磨损衰减的固件升级后行为也会变平时的基线数据到出问题时就是最重要的对照参考。存储性能这件事本质上就一句话——不是看它能跑多快而是看它在你的负载模型下能稳定多久。