Linux 磁盘 IO 慢的排查思路

Linux 磁盘 IO 慢的排查思路

磁盘 IO 慢是 Linux 服务器最常见、最隐蔽、也最容易被误判的性能瓶颈之一。 很多人一看到 top 里 wa%(iowait)很高,就直接下结论“磁盘慢了”,然后盲目换 SSD、调调度器、改文件系统参数,结果问题依旧;也有人看到 iostat %util 没到 100% 就觉得“磁盘没问题”,其实真正的瓶颈早已发生在队列深处。

下面是一套系统性、由表及里、从现象到根因的排查思路框架,适用于数据库、日志服务、文件服务器、容器存储、虚拟机宿主机等几乎所有高 IO 场景。核心思想是:先定性、再定位、最后优化

一、先明确“IO 慢”的具体表现(30 秒定方向)

IO 慢可以表现为很多种形态,不同形态指向完全不同的根因,必须先切割清楚:

表现形式最可能瓶颈类型(优先级排序)典型场景
数据库查询/写入明显变慢随机小 IO、锁等待、元数据压力MySQL/PostgreSQL/Redis
日志写入导致服务卡顿顺序大 IO + 脏页回写阻塞高并发业务日志
文件拷贝/解压/打包极慢顺序 IO 吞吐低、元数据操作多备份、解压、git 操作
容器启动/镜像拉取慢随机读 + 元数据 + overlayfs 层叠Docker/Kubernetes
整个系统响应变慢,top wa% 高混合负载、队列饱和、D 状态进程堆积综合型服务器
特定时间段突然变慢定时任务、日志切割、checkpoint、脏页集中回写cron 任务高峰

快速问自己三个问题

  1. 是随机 IO 主导还是顺序 IO 主导?
  2. 是读慢、写慢,还是读写都慢?
  3. 是否伴随大量进程进入 D 状态(不可中断睡眠)?

二、核心指标与判断标准(10 分钟内完成初步定性)

使用以下命令组合,基本就能判断出是“真 IO 慢”还是“假象”。

  1. iostat -x 1 5(最核心的 IO 观测工具)

    重点关注四项:

    • %util:磁盘利用率(最重要指标)
      • 持续 > 80–90% → 磁盘确实饱和
      • < 60% 但系统很慢 → 不是磁盘瓶颈,是队列深度或等待问题
    • await:平均每个 IO 的等待时间(包括队列等待 + 服务时间)
      • HDD:> 10–20 ms 已经明显慢
      • SSD:> 1–2 ms 开始有感觉
      • NVMe:> 0.2–0.5 ms 就值得警惕
    • svctm:磁盘实际服务时间(不含排队)
      • 与 await 差距很大 → 队列很长(排队严重)
      • 差距不大 → 磁盘本身响应慢
    • r/s + w/srkB/s + wkB/s:IOPS 与吞吐量
      • 随机小 IO:IOPS 低(几百~几千)
      • 顺序大 IO:吞吐量高(几百 MB/s)
  2. iotop -o(实时看哪个进程在狂 IO)

    快速定位 IO 发起者:MySQL、PostgreSQL、kjournald、kswapd0、容器 overlay、日志进程等。

  3. vmstat 1 5sar -d 1 5

    • bi/bo:块读/写速率
    • wa%:iowait 比例(>20–30% 持续就值得重视)
  4. dstat -cdngydstat –disk –cpu –net

    一屏看清 CPU、IO、网络、系统调用之间的关系。

三、分层排查路径(从最常见到较深层)

层 1:队列是否饱和(最常见,占比 50%+)

现象:%util 高(80–100%),await 很大(几十 ms),svctm 却不高(几 ms)

本质:磁盘本身不慢,但请求队列太长

常见原因:

  • 数据库大量随机小 IO(缺少索引、表扫描、全表更新)
  • 多进程/多容器同时疯狂写日志
  • 脏页回写集中爆发(vm.dirty_background_ratio 过大)
  • 虚拟化层 / overlayfs 元数据压力

快速验证:

  • iotop 看是否多个进程同时高写
  • sar -d 历史数据看是否有周期性 IO 尖峰

层 2:磁盘本身响应慢(硬件或驱动问题)

现象:svctm 持续偏高(HDD > 8–10ms,SSD > 0.5–1ms,NVMe > 0.1–0.2ms)

常见原因:

  • HDD 寻道时间长 + 随机 IO 多
  • SSD 写放大、SLC 缓存耗尽、温度节流
  • NVMe 队列深度不足、驱动版本老旧
  • RAID 卡缓存策略错误(WriteBack vs WriteThrough)
  • 网卡/存储网络抖动(iSCSI、FC、NVMe-oF)

验证:

  • 对比 fio 随机读写测试(4K randread/randwrite)
  • smartctl -a 查看健康状态、温度、错误日志

层 3:文件系统与元数据压力

现象:%util 高,但 IOPS 很低,await 主要消耗在元数据操作

常见原因:

  • 小文件多、创建/删除频繁(dentry/inode 缓存压力)
  • ext4/xfs 元数据 journal 阻塞
  • 目录下文件过多(> 几十万)
  • btrfs 碎片、COW 写放大

验证:

  • slabtop 看 dentry/inode 占用
  • iostat -x 看 r/s vs w/s 比例(元数据多为小读写)

层 4:内核回写与调度问题

现象:间歇性 IO 卡顿,尤其在写多读少场景

常见原因:

  • 脏页突然集中回写(jbd2、kjournald、kswapd0 吃 CPU)
  • CFQ 调度器对随机 IO 不友好(现已废弃)
  • mq-deadline / kyber / bfq 调度器参数未调优

验证:

  • perf record -a -g — sleep 10,看是否大量时间在 writeback 相关函数

四、总结:IO 慢排查的高效口诀

  1. 先 iostat -x 看 %util、await、svctm 三角关系
  2. 再 iotop 锁定哪个进程/容器在制造 IO
  3. 然后区分是随机小 IO 还是顺序大 IO
  4. 接着看 slabtop、脏页回写、元数据压力
  5. 最后考虑硬件健康、驱动、文件系统类型、调度器

一句话总结“慢”在 iostat 的 await 里,根源在 iotop 的进程里,本质在业务 IO 模式里

只要抓住这三点,90% 的磁盘 IO 慢都能在 10–30 分钟内定位到主要矛盾。

如果你当前遇到 IO 慢的问题,可以提供以下任一信息,我可以帮你快速判断方向:

  • iostat -x 1 5 的连续几组输出(重点看 %util / await / svctm)
  • iotop -o 的前几行(哪个进程 IO 最高)
  • 业务类型(数据库?日志?容器镜像?文件服务?)

这样能比单纯说“服务器 IO 很慢”更快找到根因。

Telegram
Telegram@IDCSELL