在公司做过几年性能排查,我养成一个习惯:新环境上线前,第一件事不是看CPU核数够不够,而是先摸一遍磁盘I/O的底细。很多故障表面上五花八门——接口超时、数据库连接打满、应用无响应——查到最后,有相当一部分根因都落在磁盘I/O上。磁盘I/O监控这个事,说难不难,不就是装个工具看几个数字嘛,但真到出问题的时候,很多人对着iostat一屏数字完全不知道先看哪个。这篇文章我把这几年用下来的监控思路、工具组合、阈值设置经验一次性说清楚,尽量少讲理论,多讲能直接落地的实操。1. 磁盘I/O监控到底在解决什么问题1.1 你最可能遇到的三类"磁盘假死"场景先说个我印象特别深的案例。某天下午业务方反馈系统变慢,登录都要转好几秒。我上去一看CPU和内存都挺正常,负载也不高,但整个服务就是迟钝。后来用iostat一查,%util已经打到接近100%,await飙到几百毫秒,明显是磁盘扛不住了。这种"CPU空转,磁盘拖后腿"的情况,如果你只盯着系统负载看,很难找到方向。磁盘I/O问题通常有三类典型场景:第一类是吞吐瓶颈,比如大数据量导出、日志集中写入、备份任务叠加,磁盘带宽被打满,所有读写请求都在排队。第二类是延迟突刺,平时延迟很低,一到某个时间段就飙高,通常是定时任务、日志切割、批量任务和高峰期请求撞在一起。第三类是单点故障,某块盘性能劣化或者RAID降级,整条链路被拖慢,业务层感受到的是偶发超时。这三种场景的共同点是:表面症状都在应用层,但根因都在存储层。所以监控磁盘I/O的核心价值,不是让你天天盯着曲线图看,而是出了问题的时候能快速判断"是不是磁盘的锅",以及"是哪块盘、哪个进程在搞事"。1.2 监控磁盘I/O,不等于只盯着"磁盘满了"很多人一听磁盘监控,第一反应是看磁盘剩余空间。说实话,空间告警当然重要,但I/O监控和空间监控是两码事。空间满好用,df看一眼就知道;I/O出问题,是磁盘明明还有大量空闲空间,但读写性能已经烂到没法用。举一个生活中的类比:空间监控相当于看停车场还剩多少个车位,I/O监控相当于看车辆进出停车场的速度。车位充足但出入口堵死了,车一样进不来。运维里很多"假死"故障就是这种情况——磁盘没用满,但队列堵死了。所以磁盘I/O监控真正要解决的是这几个问题:磁盘的繁忙程度到底多高,还有多少余量可以扛业务增长。请求的响应速度是否正常,是持续高延迟还是偶发突刺。具体是哪个进程在大量读写,是业务程序还是备份任务在抢资源。历史趋势如何,有没有规律性的峰值时段。下面我按这个思路,把指标、工具、排查链路逐一讲透。2. 先看懂这些核心指标,再去折腾工具2.1 一秒内搞懂 iostat 的输出逻辑监控磁盘I/O,最常用的工具就是iostat,几乎每个Linux发行版都自带或者一条命令就能装。我第一次用iostat的时候,看到满屏英文缩写也是一脸懵,后来发现它的输出逻辑其实很简单,就三层信息。第一层是CPU统计,%user、%system、%iowait这些,%iowait表示CPU等待I/O完成的时间占比。这个值高了,说明CPU在等磁盘干活,是最直观的"磁盘可能有问题"的信号。但要注意,高iowait不一定就是磁盘坏了,也可能是内存不足导致的大量换页,判断的时候要结合其他指标。第二层是设备利用率,也就是每个磁盘分区的统计,核心字段是tps、kB_read/s、kB_wrtn/s、await、%util。这就是我们要重点盯的部分。第三层是分区的读写量统计,一般看整个磁盘设备就行,分区级别的意义不大。2.2 那些让人犯迷糊的指标,逐一拆开说tps:每秒传输次数,可以理解为磁盘每秒处理了多少个I/O请求。注意它不等于读写吞吐量,一次请求可能只读几KB,也可能读几MB。看tps要和吞吐量结合,单看tps高不代表流量大。kB_read/s、kB_wrtn/s:每秒读写数据量,这是衡量吞吐的。这里有个经验值:机械盘顺序写的吞吐上限大概在150-200MB/s左右,SSD看型号,通常500MB/s起步,NVMe可以到2GB/s以上。如果吞吐长时间贴着上限,磁盘就是瓶颈。await:平均每次I/O请求的处理时间,单位毫秒。这是最值得盯的一个指标。机械盘正常情况下await在几个毫秒到十几毫秒,如果飙到几十甚至上百毫秒,说明请求在排队,磁盘处理不过来了。SSD的await通常很低,零点几到几毫秒,如果SSD的await超过几十毫秒,基本可以断定有问题。%util:设备繁忙度,也就是磁盘有百分之多少时间在处理请求,100%表示整个采样周期内磁盘一直没闲着。这里有个大坑要提醒:%util在SSD上很容易虚高,因为SSD支持并行处理多个请求,util打到100%并不代表性能到极限,反而是吞吐和延迟更能说明问题。我见过有人拿着SSD的100% util慌慌张张来问,其实业务完全没受影响。svctm:每次I/O的服务时间。这个指标在新内核里基本没有实际意义了,因为它计算的是平均服务时间,而在现代块设备层有合并、队列调度等多层机制,算出来的值参考价值不大。很多老教程还在教人看svctm,可以直接忽略。2.3 我最常用的"快速体检"命令组合平时给一台机器做磁盘I/O体检,我一般固定跑这几条命令:iostat -x 1 5-x显示扩展统计信息,1秒采样一次,共采集5次。跑完看最后几次的平均值,不要看第一次,因为第一次显示的是系统启动以来的累计平均值,参考意义不大。iostat -d -k 2 3-d只看设备,-k以KB为单位,2秒一次采集3次。这个组合适合快速看吞吐量变化。如果是定位到某块盘异常,我会加-p参数按分区看:iostat -x -p sda 1 5只看sda这块盘的分区统计,输出更清爽。还有个容易忽略的小技巧:iostat的采样间隔最好不要小于1秒,因为磁盘指标本身是累计值,采样间隔太短算出来的瞬时值抖动很大,看起来全是毛刺,反而不利于判断趋势。3. 工具选型与实操过程实录3.1 iostat 实操:三组必知参数iostat是整个磁盘I/O监控里最核心的工具,没有之一。它的参数看起来多,常用就几个,我按使用频率排个序。第一个是上面提过的-x,输出扩展数据。这里面的rrqm/s和wrqm/s代表每秒合并的读/写请求数量。合并是什么意思?就是把多个相邻的小请求合成一个大请求再发给磁盘。机械盘喜欢大请求,合并越多性能越好;但如果合并数量突然变得异常大,有可能是伴生了大量小文件随机写,反而要警惕。第二个是-m,以MB为单位输出,比默认的KB更直观。高吞吐场景下用KB看数字位数太多,换成MB一眼就知道有没有贴近磁盘上限。第三个是-y,跳过启动以来的累计数据,直接显示采样周期内的数据。加上这个参数,第一屏就有参考价值,不用浪费一次采样。我常用的完整命令是:iostat -xmy 1 5一次拿到CPU等待、设备util、吞吐、延迟全套数据,建议直接存成alias。提示:-x和-m在有些老版本里不能同时用,如果报错就分开跑,新版本没这个问题。3.2 iotop 看进程维度iostat能告诉你磁盘忙不忙,但回答不了"谁在让它忙"这个问题。这时候用iotop。iotop的用法很像top,动态刷新显示每个进程的I/O读写速率。两个关键字段是DISK READ和DISK WRITE,单位是字节每秒,一眼就能看出哪个进程在大量读写。我常用的参数:iotop -o -P-o只显示有I/O操作的进程,不显示那些全零的进程,输出干净很多;-P以进程而非线程为单位显示。如果不加-P,默认会把进程的每个线程都列一遍,输出非常乱。iotop需要root权限,这是它唯一的门槛。有些生产环境不允许随便上root,那就用下面说的pidstat。3.3 pidstat 按进程定位pidstat是另一个定位进程级I/O的好工具,它不像iotop那样动态刷新,而是按采样周期输出,适合脚本化采集。pidstat -d 1 5-d显示I/O统计,1秒采样5次。输出的kB_rd/s、kB_wr/s分别表示该进程每秒的读写量,cswch/s表示上下文切换次数,可以侧面反映进程的I/O阻塞情况。pidstat的输出是日志式的,一行一个采样点,不会覆盖屏幕,方便重定向到文件做历史分析。这是它在脚本场景下的最大优势。iotop能实时看到结果,但不好留存;pidstat正好互补。3.4 sar 长时间采集如果故障是偶发的,比如每天固定某个时段出现一次,你不可能24小时盯着屏幕等它出现。这时候需要sar。sar是sysstat包里的工具,配合cron任务做定时采集。配置方法很简单:安装sysstat包。确保/etc/cron.d/sysstat里的定时任务在运行,默认每10分钟采集一次。历史数据默认保留7天,配置文件在/etc/sysstat/sysstat,HISTORY参数控制保留天数。查看历史I/O数据用:sar -d -f /var/log/sysstat/saXXsaXX是某天的数据文件,日期是当月第几天。比如今天15号,就看sa15。-d输出设备级别的tps和吞吐,还可以加-p显示设备名而不是设备编号。结合sar -q看负载、sar -w看上下文切换,可以把故障时段的前后情况完整还原出来。sar的10分钟粒度对看趋势和规律够用,但抓偶发尖刺还是不够细。如果知道故障大概在几点,可以提前用nmon或者写个循环采集脚本把粒度缩到秒级。这就是另一套玩法了,后文会讲。3.5 短时峰值抓取有时候故障时间很短,一两次采样就被冲过去了。我处理这种问题的方式是写一个快速采集脚本,后台运行,遇到指标超过阈值就持续记录:while true; do iostat -xmy 1 1 | grep -A1 sda >> /tmp/iostat_history.log date >> /tmp/iostat_history.log sleep 1 done这个脚本简单粗暴,但有两点要注意。一是别在生产环境长时间跑,日志增长很快,磁盘没被业务打挂先被监控日志打挂了;二是要配合nohup或者systemd服务跑,别因为终端退出就断了。更专业的做法是装一个轻量级的监控agent,配置好采集周期自动落盘,这里不展开说具体厂商了,原理都是类似的:定时采集指标、存本地、告警时候拉出来看。4. 一个真实排查案例的全过程记录4.1 现象描述有一次某系统的数据库响应突然变慢,业务方反馈写入接口超时比例明显上升,但又不是完全不可用,属于"能干活但干活很费劲"的状态。我先看了系统负载和CPU,负载不高,CPU还有大量空闲,内存也够,这就让我更怀疑是磁盘。4.2 排查链路第一轮先用iostat确认磁盘状态:iostat -xmy 1 10输出里%util一直在95%以上,await平均80毫秒左右,w_await(写请求平均等待时间)超过120毫秒,w_tps写请求的每秒次数倒是不高,大概两三百。这个组合非常典型:写请求不多但每个都很慢,说明不是吞吐打满,而是某个环节在阻塞写请求。第二轮定位进程。用iotop一看,有个日志归档的进程占了将近70%的写带宽。继续查这个进程在写什么文件,发现它在把一批历史日志从本地盘拷贝到另一块盘。第三轮查为什么这个操作会阻塞主业务的写请求。看两块盘在iostat里的状态,源盘和主业务盘不是同一块,但目标盘恰好和数据库的数据文件在同一块物理盘上。归档进程的大量顺序写,把目标盘的队列占满了,数据库的随机写请求全部排队。4.3 最终定位根因就是:备份/归档任务和数据业务共用了同一块物理磁盘。逻辑上它们是独立的分区甚至独立的文件系统,但物理上共享同一个盘片和控制器,谁都不能独善其身。这里有个很常见的认知误区:分区是独立的,I/O性能却不是独立隔离的。就像一栋楼的几个房间各自独立,但供水管道是共用的,一个房间狂放水,其他房间水压就会变小。4.4 处理方案与后续短期方案:把归档任务的时间窗口从业务高峰期挪到凌晨低峰期,立刻缓解冲突。长期方案:给归档任务换挂载点,让它落到独立的存储设备上,从物理层隔离;同时给归档任务配置I/O优先级限制,用ionice把它降到idle级别:ionice -c 3 -p <pid>-c 3表示idle调度级别,只有当磁盘空闲时才会执行这个进程的I/O操作。这个命令对机械盘效果明显,SSD上效果差一些,因为SSD没有机械臂寻道的概念,I/O调度器的作用机制不一样。处理完之后,我再跑了一遍iostat,await回落到10毫秒以内,%util只有20%出头,业务方反馈接口响应恢复正常。5. 告警阈值设置与监控误区的避坑经验5.1 怎么设置阈值不误报也不漏报告警阈值这个事,我给不了你一个适用于所有环境的固定数字,因为不同存储介质、不同业务的正常水位差异太大了。但我可以给你一套设置思路。第一步,先跑一段时间的基线采集。新环境至少观察一周,用sar把每天的I/O曲线摸出来,搞清楚业务高峰和低峰的上下边界。别一上来就设置阈值,你连正常水位是多少都不知道,设出来一定瞎报。第二步,按指标类型分别设置。%util建议设两个档:警告线80%、严重线95%,但SSD环境要谨慎,参考延迟为主;await建议警告线30毫秒(机械盘)、严重线50毫秒,SSD可以压到10毫秒和30毫秒;tps和吞吐的阈值要根据业务量设置,最好用相对值——比如连续5分钟超过平时峰值的1.5倍就告警。第三步,告警一定要带上下文。比如"磁盘sda util持续5分钟超过95%"这个告警,价值远高于"磁盘util过高"。还能顺手把当时top I/O进程的信息一起带出来,排查的人一看就知道该干什么。注意:单次采样超标不要告警,磁盘指标瞬时抖动很常见,连续3-5个采样点超标再触发,误报率能降一大半。5.2 日志与历史数据保留监控不只是实时看数,更是为了事后回溯。我吃过一次亏:当时一个I/O问题持续了几天,但是没有保留历史数据,等我去查的时候故障已经过去了,连个对比的基线都没有。后来我就养成了习惯,sysstat的HISTORY参数调大,至少保留30天:# 编辑 /etc/sysstat/sysstat HISTORY=30同时把关键指标的每日汇总单独存一份,比如每天0点跑一个脚本,把当天的iostat平均数据追加到一个CSV文件里。这样月度复盘的时候直接拉出来看趋势,不用去翻几十个sa文件。5.3 需要注意的几个坑第一个坑:用%util判断SSD性能。前面说过,SSD支持并行I/O,util到100%不代表极限。我见过一块NVMe盘util长期99%,但业务延迟始终保持在1毫秒以下,完全没问题。判断SSD性能,优先看延迟和吞吐,不要被util吓到。第二个坑:忽略I/O调度器的影响。Linux默认的调度器对不同介质有不同表现,机械盘用mq-deadline或者bfq通常更好,NVMe盘用none(也就是noop)反而减少开销。如果发现I/O性能不符合预期,先看看调度器设的是什么,改调度器往往比换硬件还立竿见影。# 查看当前调度器 cat /sys/block/sda/queue/scheduler第三个坑:文件系统层面和块设备层面的混淆。有些I/O慢其实是文件系统的问题,比如inode耗尽、目录项缓存压力大、日志模式导致的写放大,iostat看不出来,要用df -i看inode使用率,用dmesg看文件系统报错。排查I/O问题别只盯一个工具,分层看才完整。第四个坑:别把iowait等同于磁盘故障。iowait高可能的原因是内存不足导致换页频繁,也可能是某进程在疯狂读写,还可能只是CPU在等待锁。看到iowait高,第一反应应该是去看内存空不空、哪个进程在写,而不是直接下"磁盘坏了"的结论。结尾:多年排查下来的一点体会做了这么多年性能排查,我最大的体会是:磁盘I/O监控不是靠某一个神奇工具,而是靠一套"实时查看、进程定位、历史回溯"的组合打法。iostat负责告诉我"磁盘现在忙不忙",iotop和pidstat负责告诉我"谁在让它忙",sar负责告诉我"这种忙是不是有规律"。三个工具各管一段,配合起来基本能覆盖日常90%以上的I/O排查场景。最后再分享一个小技巧:看完指标的疑似情况,别急着下结论,先看一眼dmesg和系统日志。磁盘硬件层面的报错、文件系统只读切换,这些信息在 iostat 里看不出来,但往往才是最要命的。把工具输出和系统日志对照着看,判断的准确率会高很多。
在公司做过几年性能排查,我养成一个习惯:新环境上线前,第一件事不是看CPU核数够不够,而是先摸一遍磁盘I/O的底细。很多故障表面上五花八门——接口超时、数据库连接打满、应用无响应——查到最后,有相当一部分根因都落在磁盘I/O上。磁盘I/O监控这个事,说难不难,不就是装个工具看几个数字嘛,但真到出问题的时候,很多人对着iostat一屏数字完全不知道先看哪个。这篇文章我把这几年用下来的监控思路、工具组合、阈值设置经验一次性说清楚,尽量少讲理论,多讲能直接落地的实操。1. 磁盘I/O监控到底在解决什么问题1.1 你最可能遇到的三类"磁盘假死"场景先说个我印象特别深的案例。某天下午业务方反馈系统变慢,登录都要转好几秒。我上去一看CPU和内存都挺正常,负载也不高,但整个服务就是迟钝。后来用iostat一查,%util已经打到接近100%,await飙到几百毫秒,明显是磁盘扛不住了。这种"CPU空转,磁盘拖后腿"的情况,如果你只盯着系统负载看,很难找到方向。磁盘I/O问题通常有三类典型场景:第一类是吞吐瓶颈,比如大数据量导出、日志集中写入、备份任务叠加,磁盘带宽被打满,所有读写请求都在排队。第二类是延迟突刺,平时延迟很低,一到某个时间段就飙高,通常是定时任务、日志切割、批量任务和高峰期请求撞在一起。第三类是单点故障,某块盘性能劣化或者RAID降级,整条链路被拖慢,业务层感受到的是偶发超时。这三种场景的共同点是:表面症状都在应用层,但根因都在存储层。所以监控磁盘I/O的核心价值,不是让你天天盯着曲线图看,而是出了问题的时候能快速判断"是不是磁盘的锅",以及"是哪块盘、哪个进程在搞事"。1.2 监控磁盘I/O,不等于只盯着"磁盘满了"很多人一听磁盘监控,第一反应是看磁盘剩余空间。说实话,空间告警当然重要,但I/O监控和空间监控是两码事。空间满好用,df看一眼就知道;I/O出问题,是磁盘明明还有大量空闲空间,但读写性能已经烂到没法用。举一个生活中的类比:空间监控相当于看停车场还剩多少个车位,I/O监控相当于看车辆进出停车场的速度。车位充足但出入口堵死了,车一样进不来。运维里很多"假死"故障就是这种情况——磁盘没用满,但队列堵死了。所以磁盘I/O监控真正要解决的是这几个问题:磁盘的繁忙程度到底多高,还有多少余量可以扛业务增长。请求的响应速度是否正常,是持续高延迟还是偶发突刺。具体是哪个进程在大量读写,是业务程序还是备份任务在抢资源。历史趋势如何,有没有规律性的峰值时段。下面我按这个思路,把指标、工具、排查链路逐一讲透。2. 先看懂这些核心指标,再去折腾工具2.1 一秒内搞懂 iostat 的输出逻辑监控磁盘I/O,最常用的工具就是iostat,几乎每个Linux发行版都自带或者一条命令就能装。我第一次用iostat的时候,看到满屏英文缩写也是一脸懵,后来发现它的输出逻辑其实很简单,就三层信息。第一层是CPU统计,%user、%system、%iowait这些,%iowait表示CPU等待I/O完成的时间占比。这个值高了,说明CPU在等磁盘干活,是最直观的"磁盘可能有问题"的信号。但要注意,高iowait不一定就是磁盘坏了,也可能是内存不足导致的大量换页,判断的时候要结合其他指标。第二层是设备利用率,也就是每个磁盘分区的统计,核心字段是tps、kB_read/s、kB_wrtn/s、await、%util。这就是我们要重点盯的部分。第三层是分区的读写量统计,一般看整个磁盘设备就行,分区级别的意义不大。2.2 那些让人犯迷糊的指标,逐一拆开说tps:每秒传输次数,可以理解为磁盘每秒处理了多少个I/O请求。注意它不等于读写吞吐量,一次请求可能只读几KB,也可能读几MB。看tps要和吞吐量结合,单看tps高不代表流量大。kB_read/s、kB_wrtn/s:每秒读写数据量,这是衡量吞吐的。这里有个经验值:机械盘顺序写的吞吐上限大概在150-200MB/s左右,SSD看型号,通常500MB/s起步,NVMe可以到2GB/s以上。如果吞吐长时间贴着上限,磁盘就是瓶颈。await:平均每次I/O请求的处理时间,单位毫秒。这是最值得盯的一个指标。机械盘正常情况下await在几个毫秒到十几毫秒,如果飙到几十甚至上百毫秒,说明请求在排队,磁盘处理不过来了。SSD的await通常很低,零点几到几毫秒,如果SSD的await超过几十毫秒,基本可以断定有问题。%util:设备繁忙度,也就是磁盘有百分之多少时间在处理请求,100%表示整个采样周期内磁盘一直没闲着。这里有个大坑要提醒:%util在SSD上很容易虚高,因为SSD支持并行处理多个请求,util打到100%并不代表性能到极限,反而是吞吐和延迟更能说明问题。我见过有人拿着SSD的100% util慌慌张张来问,其实业务完全没受影响。svctm:每次I/O的服务时间。这个指标在新内核里基本没有实际意义了,因为它计算的是平均服务时间,而在现代块设备层有合并、队列调度等多层机制,算出来的值参考价值不大。很多老教程还在教人看svctm,可以直接忽略。2.3 我最常用的"快速体检"命令组合平时给一台机器做磁盘I/O体检,我一般固定跑这几条命令:iostat -x 1 5-x显示扩展统计信息,1秒采样一次,共采集5次。跑完看最后几次的平均值,不要看第一次,因为第一次显示的是系统启动以来的累计平均值,参考意义不大。iostat -d -k 2 3-d只看设备,-k以KB为单位,2秒一次采集3次。这个组合适合快速看吞吐量变化。如果是定位到某块盘异常,我会加-p参数按分区看:iostat -x -p sda 1 5只看sda这块盘的分区统计,输出更清爽。还有个容易忽略的小技巧:iostat的采样间隔最好不要小于1秒,因为磁盘指标本身是累计值,采样间隔太短算出来的瞬时值抖动很大,看起来全是毛刺,反而不利于判断趋势。3. 工具选型与实操过程实录3.1 iostat 实操:三组必知参数iostat是整个磁盘I/O监控里最核心的工具,没有之一。它的参数看起来多,常用就几个,我按使用频率排个序。第一个是上面提过的-x,输出扩展数据。这里面的rrqm/s和wrqm/s代表每秒合并的读/写请求数量。合并是什么意思?就是把多个相邻的小请求合成一个大请求再发给磁盘。机械盘喜欢大请求,合并越多性能越好;但如果合并数量突然变得异常大,有可能是伴生了大量小文件随机写,反而要警惕。第二个是-m,以MB为单位输出,比默认的KB更直观。高吞吐场景下用KB看数字位数太多,换成MB一眼就知道有没有贴近磁盘上限。第三个是-y,跳过启动以来的累计数据,直接显示采样周期内的数据。加上这个参数,第一屏就有参考价值,不用浪费一次采样。我常用的完整命令是:iostat -xmy 1 5一次拿到CPU等待、设备util、吞吐、延迟全套数据,建议直接存成alias。提示:-x和-m在有些老版本里不能同时用,如果报错就分开跑,新版本没这个问题。3.2 iotop 看进程维度iostat能告诉你磁盘忙不忙,但回答不了"谁在让它忙"这个问题。这时候用iotop。iotop的用法很像top,动态刷新显示每个进程的I/O读写速率。两个关键字段是DISK READ和DISK WRITE,单位是字节每秒,一眼就能看出哪个进程在大量读写。我常用的参数:iotop -o -P-o只显示有I/O操作的进程,不显示那些全零的进程,输出干净很多;-P以进程而非线程为单位显示。如果不加-P,默认会把进程的每个线程都列一遍,输出非常乱。iotop需要root权限,这是它唯一的门槛。有些生产环境不允许随便上root,那就用下面说的pidstat。3.3 pidstat 按进程定位pidstat是另一个定位进程级I/O的好工具,它不像iotop那样动态刷新,而是按采样周期输出,适合脚本化采集。pidstat -d 1 5-d显示I/O统计,1秒采样5次。输出的kB_rd/s、kB_wr/s分别表示该进程每秒的读写量,cswch/s表示上下文切换次数,可以侧面反映进程的I/O阻塞情况。pidstat的输出是日志式的,一行一个采样点,不会覆盖屏幕,方便重定向到文件做历史分析。这是它在脚本场景下的最大优势。iotop能实时看到结果,但不好留存;pidstat正好互补。3.4 sar 长时间采集如果故障是偶发的,比如每天固定某个时段出现一次,你不可能24小时盯着屏幕等它出现。这时候需要sar。sar是sysstat包里的工具,配合cron任务做定时采集。配置方法很简单:安装sysstat包。确保/etc/cron.d/sysstat里的定时任务在运行,默认每10分钟采集一次。历史数据默认保留7天,配置文件在/etc/sysstat/sysstat,HISTORY参数控制保留天数。查看历史I/O数据用:sar -d -f /var/log/sysstat/saXXsaXX是某天的数据文件,日期是当月第几天。比如今天15号,就看sa15。-d输出设备级别的tps和吞吐,还可以加-p显示设备名而不是设备编号。结合sar -q看负载、sar -w看上下文切换,可以把故障时段的前后情况完整还原出来。sar的10分钟粒度对看趋势和规律够用,但抓偶发尖刺还是不够细。如果知道故障大概在几点,可以提前用nmon或者写个循环采集脚本把粒度缩到秒级。这就是另一套玩法了,后文会讲。3.5 短时峰值抓取有时候故障时间很短,一两次采样就被冲过去了。我处理这种问题的方式是写一个快速采集脚本,后台运行,遇到指标超过阈值就持续记录:while true; do iostat -xmy 1 1 | grep -A1 sda >> /tmp/iostat_history.log date >> /tmp/iostat_history.log sleep 1 done这个脚本简单粗暴,但有两点要注意。一是别在生产环境长时间跑,日志增长很快,磁盘没被业务打挂先被监控日志打挂了;二是要配合nohup或者systemd服务跑,别因为终端退出就断了。更专业的做法是装一个轻量级的监控agent,配置好采集周期自动落盘,这里不展开说具体厂商了,原理都是类似的:定时采集指标、存本地、告警时候拉出来看。4. 一个真实排查案例的全过程记录4.1 现象描述有一次某系统的数据库响应突然变慢,业务方反馈写入接口超时比例明显上升,但又不是完全不可用,属于"能干活但干活很费劲"的状态。我先看了系统负载和CPU,负载不高,CPU还有大量空闲,内存也够,这就让我更怀疑是磁盘。4.2 排查链路第一轮先用iostat确认磁盘状态:iostat -xmy 1 10输出里%util一直在95%以上,await平均80毫秒左右,w_await(写请求平均等待时间)超过120毫秒,w_tps写请求的每秒次数倒是不高,大概两三百。这个组合非常典型:写请求不多但每个都很慢,说明不是吞吐打满,而是某个环节在阻塞写请求。第二轮定位进程。用iotop一看,有个日志归档的进程占了将近70%的写带宽。继续查这个进程在写什么文件,发现它在把一批历史日志从本地盘拷贝到另一块盘。第三轮查为什么这个操作会阻塞主业务的写请求。看两块盘在iostat里的状态,源盘和主业务盘不是同一块,但目标盘恰好和数据库的数据文件在同一块物理盘上。归档进程的大量顺序写,把目标盘的队列占满了,数据库的随机写请求全部排队。4.3 最终定位根因就是:备份/归档任务和数据业务共用了同一块物理磁盘。逻辑上它们是独立的分区甚至独立的文件系统,但物理上共享同一个盘片和控制器,谁都不能独善其身。这里有个很常见的认知误区:分区是独立的,I/O性能却不是独立隔离的。就像一栋楼的几个房间各自独立,但供水管道是共用的,一个房间狂放水,其他房间水压就会变小。4.4 处理方案与后续短期方案:把归档任务的时间窗口从业务高峰期挪到凌晨低峰期,立刻缓解冲突。长期方案:给归档任务换挂载点,让它落到独立的存储设备上,从物理层隔离;同时给归档任务配置I/O优先级限制,用ionice把它降到idle级别:ionice -c 3 -p <pid>-c 3表示idle调度级别,只有当磁盘空闲时才会执行这个进程的I/O操作。这个命令对机械盘效果明显,SSD上效果差一些,因为SSD没有机械臂寻道的概念,I/O调度器的作用机制不一样。处理完之后,我再跑了一遍iostat,await回落到10毫秒以内,%util只有20%出头,业务方反馈接口响应恢复正常。5. 告警阈值设置与监控误区的避坑经验5.1 怎么设置阈值不误报也不漏报告警阈值这个事,我给不了你一个适用于所有环境的固定数字,因为不同存储介质、不同业务的正常水位差异太大了。但我可以给你一套设置思路。第一步,先跑一段时间的基线采集。新环境至少观察一周,用sar把每天的I/O曲线摸出来,搞清楚业务高峰和低峰的上下边界。别一上来就设置阈值,你连正常水位是多少都不知道,设出来一定瞎报。第二步,按指标类型分别设置。%util建议设两个档:警告线80%、严重线95%,但SSD环境要谨慎,参考延迟为主;await建议警告线30毫秒(机械盘)、严重线50毫秒,SSD可以压到10毫秒和30毫秒;tps和吞吐的阈值要根据业务量设置,最好用相对值——比如连续5分钟超过平时峰值的1.5倍就告警。第三步,告警一定要带上下文。比如"磁盘sda util持续5分钟超过95%"这个告警,价值远高于"磁盘util过高"。还能顺手把当时top I/O进程的信息一起带出来,排查的人一看就知道该干什么。注意:单次采样超标不要告警,磁盘指标瞬时抖动很常见,连续3-5个采样点超标再触发,误报率能降一大半。5.2 日志与历史数据保留监控不只是实时看数,更是为了事后回溯。我吃过一次亏:当时一个I/O问题持续了几天,但是没有保留历史数据,等我去查的时候故障已经过去了,连个对比的基线都没有。后来我就养成了习惯,sysstat的HISTORY参数调大,至少保留30天:# 编辑 /etc/sysstat/sysstat HISTORY=30同时把关键指标的每日汇总单独存一份,比如每天0点跑一个脚本,把当天的iostat平均数据追加到一个CSV文件里。这样月度复盘的时候直接拉出来看趋势,不用去翻几十个sa文件。5.3 需要注意的几个坑第一个坑:用%util判断SSD性能。前面说过,SSD支持并行I/O,util到100%不代表极限。我见过一块NVMe盘util长期99%,但业务延迟始终保持在1毫秒以下,完全没问题。判断SSD性能,优先看延迟和吞吐,不要被util吓到。第二个坑:忽略I/O调度器的影响。Linux默认的调度器对不同介质有不同表现,机械盘用mq-deadline或者bfq通常更好,NVMe盘用none(也就是noop)反而减少开销。如果发现I/O性能不符合预期,先看看调度器设的是什么,改调度器往往比换硬件还立竿见影。# 查看当前调度器 cat /sys/block/sda/queue/scheduler第三个坑:文件系统层面和块设备层面的混淆。有些I/O慢其实是文件系统的问题,比如inode耗尽、目录项缓存压力大、日志模式导致的写放大,iostat看不出来,要用df -i看inode使用率,用dmesg看文件系统报错。排查I/O问题别只盯一个工具,分层看才完整。第四个坑:别把iowait等同于磁盘故障。iowait高可能的原因是内存不足导致换页频繁,也可能是某进程在疯狂读写,还可能只是CPU在等待锁。看到iowait高,第一反应应该是去看内存空不空、哪个进程在写,而不是直接下"磁盘坏了"的结论。结尾:多年排查下来的一点体会做了这么多年性能排查,我最大的体会是:磁盘I/O监控不是靠某一个神奇工具,而是靠一套"实时查看、进程定位、历史回溯"的组合打法。iostat负责告诉我"磁盘现在忙不忙",iotop和pidstat负责告诉我"谁在让它忙",sar负责告诉我"这种忙是不是有规律"。三个工具各管一段,配合起来基本能覆盖日常90%以上的I/O排查场景。最后再分享一个小技巧:看完指标的疑似情况,别急着下结论,先看一眼dmesg和系统日志。磁盘硬件层面的报错、文件系统只读切换,这些信息在 iostat 里看不出来,但往往才是最要命的。把工具输出和系统日志对照着看,判断的准确率会高很多。