当前位置:首页>Linux>Linux 磁盘 IO 飙高,别慌,按这几步排查

Linux 磁盘 IO 飙高,别慌,按这几步排查

  • 2026-07-03 00:45:01
Linux 磁盘 IO 飙高,别慌,按这几步排查

Linux 磁盘 IO 飙高,别慌,按这几步排查

一、问题背景

磁盘 IO 是绝大多数 Linux 服务器最容易被忽视的那一环。CPU 飙高,运维同学往往能快速反应过来;但磁盘 IO 飙高时,监控曲线像锯齿,业务接口却在缓慢超时,DBA 同事和业务方都会把锅甩过来。

这些年我经手过几次典型的磁盘 IO 故障,触发原因五花八门:

  • 业务上线了一个全表扫描的定时任务,瞬时读 IO 把 SSD 的吞吐打到瓶颈;
  • 备份脚本写错路径,把 /var/log 整个目录重定向到数据库所在的磁盘;
  • 大量日志写入引发 dirty page 飙涨,内核只能疯狂回写;
  • vm.dirty_ratio
     被误调成 5,数据库进程的脏页刷不出去;
  • drop_caches
     在生产环境被半夜值班同学随手触发,触发瞬间所有冷数据回源到磁盘;
  • cgroup v1 的 blkio 限制写错了单位,把磁盘限速到几 KB,结果业务全挂;
  • 共享同一台物理磁盘的别的业务在做备份,IO 被争抢;
  • NUMA 节点绑错,CPU 跨节点访问磁盘设备,链路抖动。

这些场景的根因分布在不同的层:文件系统层、块设备层、IO 调度器层、页缓存与回写层、cgroup 层。排查的难点不是工具不会用,而是不会组合:每个工具有它擅长的视角,孤立地看很难拼出全图。

这一篇把多年来沉淀的磁盘 IO 排查方法拆开讲清楚,目标是让你在线上环境遇到 iostat 列里 await / svctm / %util 飙红时,能按一个固定流程在 10 到 30 分钟内定位到进程甚至文件级别。

二、适用场景

本文描述的排查流程适用于以下情况:

  1. 业务响应变慢、top 看到 wa 列(iowait)持续超过 20%;
  2. 监控告警 node_disk_io_time_weighted / node_disk_io_now / node_disk_reads_completed / node_disk_writes_completed 中任意一项超过基线;
  3. 数据库的 RTT / RPS 突然掉档,但 CPU、内存、网络使用率都正常;
  4. 应用日志里出现大量 io timeoutdisk slowIO ErrorStalled IO 关键字;
  5. 部署、迁移、备份、扩容过程中出现的 IO 抖动;
  6. 容器集群里某个 Pod 内的进程出现明显的磁盘 IO 等待;
  7. 云服务器出现 IO 限速(云厂商对突发 IO / IOPS 有上限);
  8. 物理机主板固件或 RAID 卡出现异常,导致磁盘响应异常。

本文不覆盖的场景:

  • NFS / CIFS / GlusterFS / CephFS 等网络文件系统的性能问题:这些文件系统的瓶颈在网络和元数据服务器,请结合 nfsstat / mountstats 等工具单独排查;
  • 虚拟化层 IO 虚拟化过度订阅问题(ESXi / KVM virtio-blk 队列拥堵):需要从宿主机和客户机两侧同时抓数据;
  • 数据库自身的 buffer pool 抖动问题:本文只在和页缓存、内核回写相互影响的角度提一下,详细调优见后续 MySQL 相关文章;
  • 文件系统本身的 bug:建议先 dmesg 看内核 oops,再升级内核 / 文件系统补丁。

三、核心知识点

3.1 Linux IO 子系统的纵向分层

一次 read() 系统调用,从应用到硬件,依次穿过:

  1. VFS 层
    :进程发起 read() / write(),VFS 做权限检查并把请求转交给具体文件系统;
  2. 文件系统层
    :ext4 / xfs / btrfs 等不同具体文件系统生成各自的 bio 结构,包含目标扇区号、长度、读 / 写标志;
  3. 通用块层
    :把 bio 合并、排序,加入对应请求队列 request_queue
  4. IO 调度器层
    mq-deadline / bfq / none / kyber 等基于多队列对上一步的请求做调度;
  5. 设备驱动层
    :PCIe NVMe 走 NVMe 驱动,SAS / SATA 走 ata / SCSI 驱动;
  6. 硬件层
    :物理磁盘执行读写,把数据 DMA 到内存中。

排查 IO 时一定要先想清楚:当前看到的指标是这一层,还是那一层。

  • iostat
     看的是块设备层(靠近硬件):
  • iotop
     看的是进程级(靠近应用);
  • blktrace
     看的是块层的请求生命周期(包含调度器);
  • perf
     跟踪内核函数,看到的是通用块层到驱动层的全过程;
  • 云厂商给的 IOPS 限流,是把整个路径强制截短。

3.2 关键指标体系:每一列到底在说什么

iostat -x 1 输出的字段,对绝大多数人来说是最关键的入口:

Device   r/s     w/s     rkB/s    wkB/s    rrqm/s  wrqm/s   %rrqm  %wrqm  r_await  w_await  aqu-sz  rareq-sz  wareq-sz  svctm   %util
nvme0n1 120.00  450.00  15360.00 8192.00  0.00    120.00   0.00   21.05  1.20     18.40    8.50    128.00    18.20    0.80     95.00

逐字段解释:

  • r/s / w/s
    :每秒读 / 写次数,注意单位是 IOPS;
  • rkB/s / wkB/s
    :每秒读 / 写数据量,单位 KB/s;
  • rrqm/s / wrqm/s
    :被合并的请求数,相邻扇区的请求会被内核合成更大的请求;
  • %rrqm / %wrqm
    :请求合并率,过低说明上层发散写入(典型:日志多线程并发写);
  • r_await / w_await
    :请求从进入设备队列到完成的总等待时间,单位 ms,含排队和服务;
  • aqu-sz
    :平均队列深度,反映设备饱和度;
  • rareq-sz / wareq-sz
    :平均每次请求大小,单位 KB,机械盘随机 IO 时这个值会非常小;
  • svctm
    :设备平均服务时间,2.x 内核后已不可靠,只能参考;
  • %util
    :设备忙于 IO 的时间比例。当 IO 不能并发执行时(机械盘单队列),%util 接近 100% 一定意味着饱和;但 NVMe SSD 并发能力很强,%util 100% 并不意味着真的满载。

判断方法:

  • r_await
     高、w_await 低:瓶颈在读,可能是数据库热数据被踢出缓存;
  • w_await
     高、r_await 低:瓶颈在写,可能是日志或回写压力;
  • await
     高、%util 不高:等待发生在队列层、设备没饱和,常见于调度器配置或队列深度不足;
  • await
     不高、%util 100%:典型 NVMe 场景,设备并发能力强,看似繁忙但响应很快;
  • aqu-sz
     大、%util 高、await 高:设备真的饱和。

3.3 IO 调度器:mq-deadline / bfq / none / kyber 该选谁

Linux 现代内核(5.x 后)默认使用多队列的 mq-deadline 或 none

  • none
    :完全不调度,直通到设备,给 NVMe SSD 这种自带队列的设备用最佳;
  • mq-deadline
    :把请求分组为 read / write FIFO,对读有期限,对写有批量,通用性强;
  • bfq
    :基于预算的公平调度,对桌面和延迟敏感场景友好,但吞吐略低;
  • kyber
    :面向多队列设备,追求低延迟;

机械盘:建议 mq-deadline 或 bfq; NVMe SSD:建议 none; SATA SSD:可以试 mq-deadline 或 bfq

3.4 页缓存与回写:那一半"看不见的 IO"来自内核

free 命令看到的 buff/cache 字段就是页缓存。应用写文件时,绝大多数情况下写到了页缓存而非真正落盘。内核有专门的回写线程 pdflush / writeback 把脏页刷到磁盘。

关键参数:

  • vm.dirty_ratio
    (默认 20):单个进程脏页占总内存比例的硬上限,达到后该进程同步回写;
  • vm.dirty_background_ratio
    (默认 10):所有脏页比例超过此值时,后台回写线程开始工作;
  • vm.dirty_expire_centisecs
    (默认 3000):脏页存活时间;
  • vm.dirty_writeback_centisecs
    (默认 500):回写线程唤醒周期;
  • vm.dirtytime_expire_seconds
    (默认 86400 秒):用于跟踪 inode 元数据(ctime/mtime)脏页寿命,与 vm.dirty_* 是并列两套机制,由内核写回时一并处理,对 ext4 / xfs 均生效。

很多人以为只要有 dirty_* 参数在就没事,实际上生产环境的常见情况是:

  • 内存大(如 256GB),dirty_ratio=20 含义是 51GB 脏页,意味着顶峰期有大量数据待写;
  • 业务大量顺序写日志,脏页堆积后写一张 SSD 跟不上;
  • dirty_background_ratio
     设过高,导致回写滞后;
  • dirty_expire_centisecs
     设过长,老脏页滞留。

排查时要观察 nr_dirty / nr_writeback / nr_unstable 这几个值:

cat /proc/vmstat | egrep 'dirty|writeback'

如果 nr_writeback 持续很高,说明回写线程一直很忙;如果 nr_dirty 持续很高,说明写入速率超过回写速率。

3.5 工具链一览

工具
视角
适用场景
iostat
块设备层
全局瓶颈判断、IOPS / 吞吐 / 延迟基线
iotop
进程级
找谁在狂写、狂读
pidstat -d
进程级
看进程级 IO 统计、不需要 iotop
vmstat
内存 / 系统
看 swap / cs / wa,关注 bi / bo
dstat
多维度组合
同时观察 CPU / 内存 / IO / 网络
blktrace
 / biosnoop
块层
单个请求从发出到完成的完整路径
perf
内核函数
跟踪内核栈,看清楚是否卡在哪一层
bpftrace
内核 tracepoint
比 perf 更轻量,可以定制脚本
fio
用户态压测
测盘健康度、对比基线
dd
顺序读写
极简的吞吐测试,不建议用于随机 IO
smartctl
硬件
看磁盘 SMART 信息,硬件是否健康

iotop 和 pidstat -d 的区别:iotop 在很忙的机器上会有较大开销(每行打印会触发 /proc 读取),适合短时间观察;pidstat -d 是采样式的,适合放进监控脚本。

四、整体排查思路

4.1 由顶到底的分层定位

无论 IO 表现为什么样子,都建议按下面这个顺序逐步深入:

1. 顶层判断:是不是真的是 IO?
   - top 看 %wa
   - uptime 看 load average 跟 CPU 核数差距
   - vmstat 1 看 bi / bo / cs / us / sy / id / wa
   - 确认当前指标是不是 IO 主导

2. 全局层:iostat -x 1 5
   - 哪块盘在忙
   - 是读主导还是写主导
   - 延迟分布
   - 是否有大量合并请求

3. 进程层:iotop / pidstat -d 1
   - 哪个进程在写 / 读
   - 是否能 kill 或限速

4. 文件层:lsof -p <pid>
   - 进程打开了哪些文件
   - 是否触犯了不该写的路径

5. 内核层:dmesg / /proc/vmstat / /proc/pressure/io
   - 是否有 IO 错误
   - 脏页状态
   - psiri 压力

6. 调度层:cat /sys/block/*/queue/scheduler
   - 当前调度器
   - 队列深度
   - readahead

7. 硬件层:smartctl -a / nvme smart-log / megacli / sas3ircu
   - RAID 卡状态
   - 磁盘 SMART
   - 硬件告警

4.2 排查流程图

        ┌─────────────────────────┐
        │ 收到"IO 慢了"的工单/告警 │
        └─────────────┬───────────┘
                      │
       ┌──────────────▼──────────────┐
       │ top / uptime: 是 %wa 高吗? │
       └───────┬───────────────┬────┘
              否               是
               │               │
               ▼               ▼
         排查 CPU / 内存       ┌──────────────────────────┐
                               │ iostat -x 1 5: 哪块盘?  │
                               └──────────┬───────────────┘
                                          │
                ┌─────────────────────────┼────────────────────┐
                ▼                         ▼                    ▼
            读主导                     写主导                混合
                │                         │                    │
                ▼                         ▼                    ▼
      iotop 找读进程              iotop 找写进程          多个盘?
      pidstat -d 1               pidstat -d 1           各盘分别
      看看谁在扫表                看 dirty* 回写情况     定位饱和盘
                                       │
                                       ▼
                              dmesg / vmstat
                              dirty 比例 / nr_writeback
                              调度器 / 队列深度
                                       │
                                       ▼
                                 应用层修复
                                 内核参数调整
                                 IO 调度器切换

4.3 排查时的协作建议

遇到 IO 类故障,多半会跨团队。提前和开发、DBA、云厂商沟通可以减少反复取证:

  • 找业务侧要最近变更清单:发布、定时任务、扩容、回滚;
  • 找 DBA 要数据库的慢查询、锁等待、行锁、Buffer Pool;
  • 找云厂商要 IOPS / 吞吐限速的真实值(很多云平台要在控制台翻才能看到);
  • 找硬件供应商要 SMART 日志(云厂商往往要在工单系统里提单)。

五、实战步骤

下面按编号把每一步的执行细节展开。每个步骤都包含:目的 / 命令 / 预期输出 / 异常表现 / 判断逻辑 / 下一步动作。

5.1 第一步:iostat -x 1 5,看全局 IO

目的:判断是否真的存在 IO 瓶颈,是哪块盘,是读还是写。

命令:

bash
# 安装 sysstat(RHEL/CentOS)
yum install -y sysstat

# Debian/Ubuntu
apt-get update && apt-get install -y sysstat

# 取样 5 次,间隔 1 秒
iostat -x 1 5

预期输出(健康):

Device   r/s    w/s    rkB/s    wkB/s    aqu-sz   await   svctm   %util
nvme0n1  8.00   32.00  128.00   512.00   0.20     0.80    0.10    4.00
sda      0.10   0.05   4.00     1.00     0.00     0.50    0.05    0.10

异常表现:

  • 单盘 %util 持续 ≥ 80%;
  • await
     ≥ 5ms(机械盘)/ ≥ 1ms(NVMe);
  • aqu-sz
     ≥ 4,队列堆积;
  • 写主导时 wkB/s 持续打到磁盘标称带宽。

判断逻辑:

  • 多块盘都有问题:瓶颈在更高层(应用 / 内核 / 网络存储等);
  • 单一盘忙:定位到这块盘的挂载点和上层业务;
  • 持续写高但 await 不高:常见于 SSD 顺序大块写;
  • 持续写高 await 也高:很可能写饱和,物理跟不上了。

下一步动作:

  • 写出忙的盘 lsblk 找出挂载点;
  • 用 df -h /<mountpoint> 看剩余容量;
  • 用 mount | grep <mountpoint> 看文件系统类型;
  • 进到下一步找具体进程。

5.2 第二步:iotop -oP,定位进程元凶

目的:判断是哪个进程在读写这块盘。

命令:

bash
yum install -y iotop   # 安装
iotop -oP              # 只显示有 IO 活动的进程,不显示 idle

参数说明:

  • -o
    :只显示正在读写磁盘的进程;
  • -P
    :只显示进程,不显示线程;
  • -a
    :累积 IO 而非实时速率,适合短时间诊断;
  • -d 1
    :刷新间隔 1 秒;
  • -n 5
    :总共显示 5 次后退出。

预期输出(部分):

Total DISK READ:       0.00 B/s | Total DISK WRITE:    85.34 M/s
Current DISK READ:     0.00 B/s | Current DISK WRITE:  90.12 M/s
   TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO    COMMAND
 12345 ?Apid  mysql      0.00 B/s    65.12 M/s  0.00 %      0.00 % mysqld
 18890 ?Apid  root       0.00 B/s    20.00 M/s  0.00 %      0.00 % python3 /opt/bak.sh

异常表现:

  • 出现多个业务进程同时大量写:可能存在定时任务并发触发;
  • 出现 bash / sh 写:可能是某个 cron job 或脚本;
  • 出现 sh / bash 写 /var/log:清理日志或转储业务;
  • 出现 rsync / tar / cp / dd:文件级搬迁。

判断逻辑:

  • 进程能停 → kill 或限速;
  • 进程是数据库 → 让 DBA 介入收慢查询;
  • 进程是系统组件 → 排查是否有外部误调用;
  • 进程是某个用户的脚本 → 联系脚本负责人。

下一步动作:

  • lsof -p <PID>
     看进程打开了哪些文件;
  • ls -la /proc/<PID>/fd
     看文件描述符;
  • readlink /proc/<PID>/cwd
     看进程工作目录;
  • cat /proc/<PID>/io
     看总 IO 计数。

风险提示:iotop -oP 必须以 root 运行;线上环境使用前要通知相关方,因为 IO 高时 iotop 自己也会产生少量开销。

5.3 第三步:pidstat -d 1 5,看进程级 IO 统计

目的:iotop 抓不住的细节(被剔出的进程、短暂的尖刺),用 pidstat 抓历史。

命令:

bash
# 安装
yum install -y sysstat    # pidstat 在 sysstat 包里

# 看所有进程,每秒 1 次,共 5 次
pidstat -d 1 5

# 看指定进程
pidstat -d -p 12345 1 5

# 看线程
pidstat -d -t -p 12345 1 5

参数说明:

  • -d
    :只显示 IO 统计;
  • -p
    :指定 PID;
  • -t
    :同时显示线程;
  • -w
    :上下文切换(结合用)pidstat -dw 同时看 IO 和上下文切换;
  • -u
    :CPU(同时排查 IO 与 CPU 比例)。

预期输出(异常):

13:32:11  UID   PID   kB_rd/s  kB_wr/s  kB_ccwr/s  Command
13:32:13  27    1234  0.00     6500.00  0.00       mysqld
13:32:14  27    1234  0.00     8500.00  0.00       mysqld

判断逻辑:

  • 同一进程重复出现在多次采样中 → 这不是抖动,是持续 IO;
  • 多个进程交替出现 → 看看是不是定时任务;
  • 写入速率极高(GB/s 级别)→ 多半是逻辑卷 / RAID 重映射操作。

下一步动作:

  • 拿到 PID 后用 lsof -p <PID> 看具体文件;
  • ionice -p <PID>
     看进程的 IO 调度类和优先级;
  • cat /proc/<PID>/io
     查累计 IO 字节数;
  • 把可疑进程的 IO 优先级调低(class 3),前提是不能影响业务可用性。

5.4 第四步:vmstat 1,看内存与 IO

目的:判断 IO 高是不是内存回收 / swap 引发的,顺便看上下文切换与系统调用。

命令:

bash
vmstat 1 10

预期输出(健康):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si  so    bi    bo    in   cs   us  sy  id  wa  st
 2  0      0 204800 4096  409600    0   0     8    32  1024 2048  20  10  70   0   0

字段对照:

  • si / so
    :swap in / swap out,原则上应该是 0;
  • bi / bo
    :blocks in / blocks out,块设备的读写数据量,单位 KB/s;
  • cs
    :上下文切换,过高意味着内存压力大;
  • us / sy / id / wa
    :用户态 / 系统态 / 空闲 / iowait;
  • b
    :处于不可中断睡眠状态的进程数(D 状态),IO 高时容易堆。

异常表现:

  • wa
     持续 ≥ 20:IO 主导;
  • so > 0
    :正在换出,物理内存不足,建议先加内存,不要先调 IO;
  • b > 5
    :D 状态进程堆积;
  • cs > 100000
    :上下文切换夸张,多半是内存压力。

判断逻辑:

  • wa
     高 + so=0 + b 较高:纯 IO 瓶颈;
  • wa
     高 + so > 0:先解决内存(swap 引发的 IO 比应用 IO 难处理得多);
  • wa
     高 + b=0:可能是网络 IO(vmstat 不能区分)。

下一步动作:

  • 看内存:free -hcat /proc/meminfo
  • 看 swap:swapon --showvmstat 1
  • 调出 D 状态进程:ps -eo pid,stat,cmd | awk '$2 ~ /D/' 或 cat /proc/<PID>/stack

5.5 第五步:dstat -cdngy,多维并行观察

目的:在 IO 飙高的同时记录 CPU、磁盘、网络、内存、页面活动,方便事后回溯。

命令:

bash
yum install -y dstat

# 1 秒一次,输出 CSV 格式到文件
dstat -cdngy --output /tmp/ds.csv 1 60

# 不写文件,就看屏幕
dstat -cdngy 1 30

参数:

  • -c
    :CPU;
  • -d
    :磁盘 read/write;
  • -n
    :网络 receive/send;
  • -g
    :页面换入换出;
  • -y
    :system 中断/上下文切换;
  • --output
    :输出文件。

预期输出(异常):

----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw
 20  10   0  70   0   0|  12M  156M|   0     0 |   0    0 |1230  3400

判断逻辑:

  • wai
     列持续高 + writ 持续高:写 IO 瓶颈;
  • wai
     列持续高 + read 持续高:读 IO 瓶颈;
  • paging out > 0
    :内存真的不够。

下一步动作:

  • 输出到 CSV 后可以交给同事在 Excel 里画图;
  • 关联 pidstat -d 一起用,定位具体进程;
  • 留下时间戳、与告警时间戳匹配。

5.6 第六步:perf trace / bpftrace biosnoop,看内核栈

目的:当 iotop 都抓不到峰值(因为持续时间太短),需要 tracepoint 工具。

命令(bpftrace):

bash
# 安装 bpftrace
yum install -y bpftrace

# 抓到一段后 Ctrl+C 退出
bpftrace -e '
kprobe:blk_mq_start_request {
  printf("%d %s %d\n", pid, comm, args->rq->cmd_flags);
}
'

更复杂的脚本(biosnoop):

bash
bpftrace -e '
tracepoint:block:block_rq_issue
/args->rwbs == "W"/ { @start[arg0] = nsecs; }
tracepoint:block:block_rq_complete
/args->rwbs == "W"/ /@start[arg0]/ {
  @usecs = hist((nsecs - @start[arg0]) / 1000);
  delete(@start[arg0]);
}
'

interval:s:1 { print(@usecs); clear(@usecs); }
'

判断逻辑:

  • 内核栈卡在 blk_mq_start_request 队列 → 队列深度饱和;
  • 卡在 __blk_mq_run_hw_queue → 调度器问题;
  • 卡在 nvme_irq 之后 → 设备驱动问题;
  • 卡在 filemap_get_pages → 页缓存问题。

下一步动作:

  • 调整调度器或队列深度:/sys/block/<dev>/queue/scheduler
  • 调大容量队列:echo 1024 > /sys/block/<dev>/queue/nr_requests
  • 确认驱动版本:ethtool -i <dev> / modinfo nvme

5.7 第七步:fio 做磁盘基线测试

目的:在定位进程后,判断磁盘本身是否还"健康"。如果 fio 也跑不出标称性能,那是物理 / 云端 IO 限速。

命令:

bash
yum install -y fio

# 顺序写 4GB,评价盘能力
fio --name=seq_write --filename=/mnt/test.bin \
    --rw=write --bs=1M --size=4G --numjobs=1 \
    --runtime=60 --time_based --ioengine=libaio \
    --direct=1 --group_reporting

# 随机写 4K(最常见的数据库场景)
fio --name=rand_write_4k --filename=/mnt/test.bin \
    --rw=randwrite --bs=4k --size=4G --numjobs=4 \
    --runtime=60 --time_based --ioengine=libaio \
    --direct=1 --iodepth=32 --group_reporting

# 混合读写 70/30
fio --name=mix --filename=/mnt/test.bin \
    --rw=randrw --rwmixread=70 --bs=4k --size=4G \
    --runtime=60 --time_based --ioengine=libaio \
    --direct=1 --iodepth=32 --group_reporting

风险提醒:fio 必须在不会影响业务的空闲盘或临时文件路径执行。误在 /var/lib/mysql 执行会直接打爆数据库所在盘;务必先用 --directory <dir> 测试;测试前确认 fio --eta=never 时不能阻塞其他作业。

判断逻辑:

  • 顺序写达不到盘标称带宽:硬件或 RAID 卡问题;
  • 随机 4K 写远低于标称 IOPS:盘老化或云厂商限制;
  • 随机读写抖动大:磁盘控制器或 RAID BBU 问题。

下一步动作:

  • 把测试结果和厂商标称对比,差距 30% 内算正常;
  • 对比 iostat -x 和 fio 的延迟分布;
  • 联系硬件供应商或云厂商提工单。

5.8 第八步:判断 IO 调度器与队列深度

目的:IO 调度器和队列深度对延迟影响极大,需要在系统层确认是否合理。

命令:

bash
# 当前调度器
cat /sys/block/nvme0n1/queue/scheduler
# 输出:[mq-deadline] kyber bfq none

# 切换调度器(立即生效,重启失效)
echo kyber > /sys/block/nvme0n1/queue/scheduler

# 队列深度
cat /sys/block/nvme0n1/queue/nr_requests

# 当前 IO 队列深度
cat /sys/block/nvme0n1/queue/queue_depth

# readahead
cat /sys/block/nvme0n1/queue/read_ahead_kb

# rotational(0 表示非转动盘,1 表示转动盘)
cat /sys/block/nvme0n1/queue/rotational

判断逻辑:

  • NVMe 盘最佳调度器是 none,但部分内核(4.x)默认还是 mq-deadline,需要手动切;
  • nr_requests
     默认可能只有 128,机械盘随机 IO 大时建议调高到 256-512;
  • read_ahead_kb
     默认可能是 128 KB,机械盘顺序读场景调到 1024+,随机读场景调到 128 不要改。

下一步动作:

  • 用 udev 规则固定调度器;
bash
cat > /etc/udev/rules.d/60-io-scheduler.rules << 'EOF'
# 为 nvme 设备设置 none 调度器
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
# 为 sata ssd 设置 mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# 为 hdd 设置 bfq
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
EOF
udevadm control --reload-rules
udevadm trigger
  • 在 /etc/sysctl.d/99-io.conf 调内核参数(详见配置示例一节)。

5.9 第九步:/proc/pressure/io 看 PSI 压力

目的:内核 4.20+ 开始提供 Pressure Stall Information,能更准确地衡量 IO 对进程的拖累。

命令:

bash
cat /proc/pressure/io

# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0

字段说明:

  • some
     行:至少有 1 个进程在等 IO 的时间比例(5 秒内);
  • full
     行:所有进程都在等 IO 的时间比例;
  • avg10 / avg60 / avg300
    :滑动窗口;
  • total
    :累计时间,单位 us。

判断逻辑:

  • some > 30%
    :IO 压力已经直接影响业务;
  • full > 5%
    :所有进程都堵了,性能严重受损;
  • total
     增长但 avg 平稳:压力稳定。

下一步动作:

  • 在 Prometheus pressure_io_waiting_seconds_total 中告警(详见第八节);
  • 把数据放进 dashboard 长期追踪;
  • 如果只 full 高,多半是单进程(如数据库)被 IO 卡死。

5.10 第十步:smartctl -a / nvme smart-log,最后看硬件

目的:所有软件层都查完还没解决,看硬件。

命令:

bash
yum install -y smartmontools

# SATA 机械盘 / SATA SSD
smartctl -a /dev/sda

# NVMe
smartctl -a /dev/nvme0n1

# 短自检
smartctl -t short /dev/sda

# 长自检(后台)
smartctl -t long /dev/sda

# 看自检日志
smartctl -l selftest /dev/sda

# 看错误日志
smartctl -l error /dev/sda

判断逻辑:

  • Reallocated_Sector_Ct
    (SMART 5)> 0:磁盘已经有坏块重映射,继续上涨说明盘在死亡;
  • Current_Pending_Sector
    (SMART 197)> 0:等待重映射的扇区,临近危险;
  • Offline_Uncorrectable
    (SMART 198)> 0:有不能纠正的错误;
  • NVMe critical_warning 非 0:硬件告警;
  • Percentage Used
     接近 100:SSD 寿命耗尽。

下一步动作:

  • 立即备份数据;
  • 联系存储或云厂商换盘;
  • 用 ddrescue / dd 抢救数据前先评估。

风险提示:smartctl -t long /dev/sda 是后台长自检,会加大 IO 压力;生产环境避免在负载高峰执行。

六、常用命令汇总

下面这些命令已经在我自己的环境里沉淀成了 IO 故障排查的"急救包"。

6.1 综合信息收集脚本

bash
#!/bin/bash
# io-snapshot.sh - 一次性采集 IO 故障的现场信息
# 用法: sudo bash io-snapshot.sh
# 注意: 不修改任何数据,只读采集

OUT=/tmp/io-snapshot-$(date +%Y%m%d-%H%M%S)
mkdir -p "$OUT"
cd"$OUT" || exit 1

echo"[*] 采集系统基本信息 ..."
uname -a > system.info
cat /etc/os-release >> system.info
date >> system.info
uptime >> system.info
free -h > mem.free
cat /proc/meminfo > mem.proc

echo"[*] 采集块设备层指标 ..."
iostat -x 1 5 > iostat.txt 2>&1
iostat -d 1 5 > iostat-d.txt 2>&1
lsblk > lsblk.txt 2>&1
df -h > df.txt 2>&1
mount > mount.txt 2>&1

echo"[*] 采集进程级指标 ..."
top -bn2 > top.txt 2>&1
ps auxf > ps.txt 2>&1
ps -eo pid,ppid,stat,etime,comm > ps-stat.txt 2>&1

echo"[*] 采集 IO 重点进程 ..."
for p in $(ps -eo pid --sort=-%cpu | head -20); do
    [ -d /proc/$p ] || continue
echo"PID=$p comm=$(cat /proc/$p/comm 2>/dev/null)" >> proc.io
cat /proc/$p/io 2>/dev/null >> proc.io
echo"----" >> proc.io
done

echo"[*] 采集调度器与内核参数 ..."
for d in /sys/block/*; do
echo"$d:"
echo"  scheduler=$(cat $d/queue/scheduler)"
echo"  nr_requests=$(cat $d/queue/nr_requests)"
echo"  read_ahead_kb=$(cat $d/queue/read_ahead_kb)"
echo"  rotational=$(cat $d/queue/rotational)"
cat$d/stat 2>/dev/null | awk '{print "  stat="$0}'
done > scheduler.txt

sysctl vm.dirty_* > sysctl-dirty.txt 2>&1
cat /proc/vmstat > vmstat.txt 2>&1
cat /proc/pressure/io > psi-io.txt 2>&1

echo"[*] 采集日志与硬件状态 ..."
dmesg -T > dmesg.txt 2>&1
dmesg -T | grep -iE 'i/o|error|ata|nvme|scsi' > dmesg-io.txt 2>&1
last -100 > last.txt 2>&1

tar czf /tmp/io-snapshot.tgz "$OUT"
echo"[*] 已打包到 /tmp/io-snapshot.tgz"
ls -la /tmp/io-snapshot.tgz

注意:

  • 只读取,绝不写;
  • 在 /tmp 下操作,但 /tmp 可能被限制目录权限,可以在脚本开头确认;
  • 不要把脚本路径指向有问题的盘;
  • 退出码要保留,建议加 set -e,但别让失败中断整体采集,把每个 echo 都包到 “尝试” 段。

6.2 一句话现场抓取命令

bash
# top 排序进程
top -bn1 -o %CPU | head -20

# iotop 单次快截图
iotop -bn1 -oP | head -20

# pidstat 单次抓
pidstat -d 1 5 | tail -20

# vmstat 单次抓
vmstat 1 5

# dstat 多维单次抓
dstat -cdngy 1 5

# 找出所有 D 状态进程并显示内核栈
ps -eo pid,ppid,stat,etime,comm | awk '$2 ~ /D/'
for p in $(ps -eo pid,stat | awk '$2 ~ /D/{print $1}'); do
echo"== PID $p =="
cat /proc/$p/stack 2>/dev/null
echo
done

6.3 调度器与内核参数快速调整

bash
# 看当前调度器
cat /sys/block/*/queue/scheduler | uniq -c

# 切到 none
echo none | tee /sys/block/nvme*/queue/scheduler

# 提高 nr_requests
echo 512 > /sys/block/sda/queue/nr_requests

# 调 read_ahead
echo 1024 > /sys/block/sda/queue/read_ahead_kb

# 调内核 dirty 参数(临时)
sysctl -w vm.dirty_ratio=10
sysctl -w vm.dirty_background_ratio=5

6.4 监控数据采集脚本

bash
#!/bin/bash
# io-record.sh - 长期记录机器 IO 状态到 log
INTERVAL=${1:-5}
LOG=/var/log/io-record-$(hostname).log
mkdir -p $(dirname"$LOG")
echo"ts,rrqm/s,wrqm/s,r/s,w/s,rkB/s,wkB/s,avgrq-sz,avgqu-sz,await,svctm,%util" > "$LOG"
iostat -dx "$INTERVAL" | awk -v OFS=',''
NR > 3 && $1 ~ /^[a-z]/ {
    print systime(), $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
}
'
 >> "$LOG"

用 nohup 让它在后台跑:

bash
chmod +x io-record.sh
nohup ./io-record.sh 5 >/dev/null 2>&1 &

风险提示:这种后台监控脚本自身有少量 IO 开销,在已经爆满的盘上可能进一步加剧问题,建议在排查场景而不是长期监控中使用。

七、配置示例

7.1 IO 调度器 udev 规则

bash
cat > /etc/udev/rules.d/60-io-scheduler.rules << 'EOF'
# NVMe -> none(直通)
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"

# SATA SSD / 虚拟机虚拟盘 -> mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"

# 机械盘 -> bfq 或 mq-deadline
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
EOF

udevadm control --reload-rules
udevadm trigger

验证:

bash
lsblk -o NAME,SCHED
# NAME       SCHED
# nvme0n1    none
# sda        bfq

7.2 内核 dirty 参数

/etc/sysctl.d/99-io-dirty.conf

bash
# 控制内核脏页比例
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20

# 老化时间
vm.dirty_expire_centisecs = 1500
vm.dirty_writeback_centisecs = 100

# 边界保护
vm.dirtytime_expire_seconds = 43200

参数说明:

  • dirty_background_ratio
    :后台回写开始的比例,数值越低越早开始回写;
  • dirty_ratio
    :进程触发同步回写的硬上限;
  • dirty_expire_centisecs
    :脏页寿命(厘秒),过高会导致旧脏页积压;
  • dirty_writeback_centisecs
    :回写线程唤醒间隔(厘秒),值越小越频繁。

风险提示:把 dirty_background_ratio 调成 1 等激进值会让回写线程长期处于满负载,反而造成 IO 抖动,慎用。

应用:

bash
sysctl --system
# 或
sysctl -p /etc/sysctl.d/99-io-dirty.conf

7.3 cgroup v1 blkio 限制

/etc/systemd/system/io-limit.slice

bash
[Unit]
Description=IO limited slice
DefaultDependencies=no

[Slice]
CPUWeight=100
MemoryHigh=2G
IOWeight=100
IOReadBandwidthMax=/dev/nvme0n1 50M
IOWriteBandwidthMax=/dev/nvme0n1 30M
IOReadIOPSMax=/dev/nvme0n1 5000
IOWriteIOPSMax=/dev/nvme0n1 4000

校验命令:

bash
systemd-cgtop
# 看哪个 slice 占多少 IO

# 永久生效
systemctl set-property my-service.slice IOReadBandwidthMax=/dev/nvme0n1 50M
systemctl set-property my-service.slice IOWriteBandwidthMax=/dev/nvme0n1 30M

风险提示:

  • IOWeight
     是相对权重,不是带宽上限。如要硬上限用 IOReadBandwidthMax / IOWriteBandwidthMax
  • 在 cgroup v1 blkio 老版本内核(3.x)中,限制不一定精确;
  • cgroup v2 在 RHEL 8 / CentOS 8+ / Ubuntu 22+ 上效果更好,建议升级。

7.4 cgroup v2 IO 限制示例

/etc/systemd/system/io-limit-v2.slice

bash
[Slice]
CPUWeight=100
MemoryHigh=2G
IOWeight=100
IOReadBandwidthMax=/dev/nvme0n1 50M
IOWriteBandwidthMax=/dev/nvme0n1 30M

cgroup v2 在 mount | grep cgroup2 出现的机器上工作。

7.5 NVMe 多队列优化

/etc/modprobe.d/nvme.conf

bash
# NVMe 多队列
options nvme io_timeout=30 poll_queues=8

应用:

bash
dracut -f   # RHEL/CentOS
update-initramfs -u   # Debian/Ubuntu

风险提示:内核参数调整必须先在测试机验证,再灰度到生产;dracut -f 会重新生成 initramfs,执行失败的话系统可能无法启动;建议保留旧 initramfs。

7.6 sysctl 完整推荐值(参考)

/etc/sysctl.d/99-io.conf

bash
# 脏页控制
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 1500
vm.dirty_writeback_centisecs = 100

# 内存回收优化
vm.swappiness = 10

# IO 调度相关
vm.page-cluster = 0

# 文件系统缓存压力
vm.vfs_cache_pressure = 50

# PSI(Pressure Stall Information)由内核 4.20+ 自动开启,
# 关闭需要在 boot 阶段加 psi_disabled 参数;此处不通过 sysctl 控制。

风险提示:swappiness=10 是相对激进的设置(避免用 swap),但对某些数据库场景不友好;page-cluster=0 在高 IO 场景下可能反向优化,需要按机器实际负载调。

bash
# 验证 swappiness
cat /proc/sys/vm/swappiness

# 验证 vfs_cache_pressure
cat /proc/sys/vm/vfs_cache_pressure

# 验证 PSI io
cat /proc/pressure/io

八、日志与指标观察方法

8.1 dmesg 中的 IO 关键字

bash
dmesg -T | grep -iE 'i/o error|read error|write error|medium|timeout|nvme|ata|scsi'

关键关键字:

  • I/O error
    :块设备 IO 错误,可能盘老化或链路故障;
  • Medium Error
     / Hardware Error:硬件已经出故障;
  • device timeout
    :IO 提交后没在规定时间完成;
  • resetting link
    :链路重置,RAID 卡或 HBA 卡异常;
  • nvc=nvme0n1: Device not ready
    :NVMe 控制器设备脱机;
  • soft lockup
    :内核长时间没调度,配合 B 状态判断是否 IO 引发的。

8.2 /sys/block/*/stat 的字段含义

bash
cat /sys/block/nvme0n1/stat
# 字段  read_io  read_merged  read_sectors  read_ticks  write_io  write_merged  write_sectors  write_ticks  io_in_progress  io_ticks  io_ticks_total
  • read_merged / write_merged
    :合并请求数量;
  • read_ticks / write_ticks
    :单请求总时长 ms 累计;
  • io_in_progress
    :正在执行的 IO 数;
  • io_ticks_total
    :整个设备忙着的时间总和,与 %util 关联。

这种 stat 可以脚本化采集,做长期趋势:

bash
cat /sys/block/nvme0n1/stat | awk '{print "read_io="$1, "write_io="$5, "io_in_progress="$9}'

8.3 Prometheus 监控指标

node_exporter 暴露的 IO 关键指标:

指标名
类型
含义
node_disk_io_now
gauge
当前正在进行的 IO 操作
node_disk_io_time_seconds_total
counter
设备繁忙时间累计
node_disk_io_time_weighted_seconds_total
counter
设备带宽时间累计,反映平均并发
node_disk_reads_completed_total
counter
读完成次数
node_disk_writes_completed_total
counter
写完成次数
node_disk_read_bytes_total
counter
读字节数
node_disk_writes_bytes_total
counter
写字节数
node_disk_read_time_seconds_total
counter
读总时间
node_disk_write_time_seconds_total
counter
写总时间
node_disk_*_merged_total
counter
合并请求数
node_disk_pending_operations
gauge
当前未完成的 IO 数
node_pressure_io_waiting_seconds_total
counter
PSI some
node_pressure_io_stalled_seconds_total
counter
PSI full

推荐告警规则示例(PromQL):

yaml
# IO 队列堆积
-alert:DiskIOPendingHigh
expr:node_disk_pending_operations>32
for:5m

# IO 利用率
-alert:DiskIOUtilHigh
expr:|
    rate(node_disk_io_time_seconds_total[5m]) > 0.85
for:5m

# 单盘读写延迟
-alert:DiskIOLatencyHigh
expr:|
    (rate(node_disk_read_time_seconds_total[5m]) /
     rate(node_disk_reads_completed_total[5m])) * 1000 > 20
for:5m

# PSI some 持续高
-alert:PsiIOSomeHigh
expr:|
    rate(node_pressure_io_waiting_seconds_total[5m]) > 0.3
for:5m

说明:

  • 阈值需要结合业务基线调整,“以实际基线为准”;
  • 块设备名匹配规则是 node_disk_* 自动发现 /sys/block 下设备;
  • 容器场景需要 cAdvisor 提供 container_fs_* 指标。

8.4 业务侧 IO 行为采集

除了内核级,业务侧的 IO 行为数据同样关键:

  • sar -b 1 5
    :sar 提供的 tps / rtps / wtps / bread/s / bwrtn/s 统计;
  • sar -d 1 5
    :每设备活动统计;
  • pidstat -d
    :进程级;
  • 数据库 SHOW GLOBAL STATUS LIKE 'Innodb_data_*':InnoDB 内部 IO;
  • 应用日志中的 io wait / flush 关键字。
bash
yum install -y sysstat
sar -b 1 5
sar -d 1 5

风险提示:sar 是采样式,但对内核 proc 文件的访问有少量开销;线上环境建议在采样期间不要改其他内核参数。

8.5 长期趋势分析方法

bash
# 看 7 天前到今天的 IO 曲线(CSV)
zcat /var/log/sysstat/sa*.gz | sadf -d -- -p -r -j | grep -E 'nvme0n1|sda'

sadf 输出的是 RPN,可以导入 Grafana / Kibana。

8.6 把 IO 指标对接业务慢请求日志

业务侧的慢请求日志通常带 trace_id。在 OpenTelemetry 体系下,可以把 host 维度的 io.wait.time 注入到 trace span:

yaml
# OpenTelemetry Collector 配置示例
processors:
resourcedetection:
detectors: [systemec2]
attributes/io:
actions:
-key:io.disk.await
from_attribute:host.disk.await

这样在慢请求 trace 里能直接看到这台机器当时的 IO 情况。

九、排查路径

针对不同现象,按决策树分以下几条典型路径。

9.1 %util 高但 await 不高

现象:

  • iostat -x 1
     的 nvme0n1 %util 长期在 80%+
  • await
     在 0.5ms 左右

判断:设备并发能力很强(NVMe SSD),看似繁忙但延迟低,多半是业务真的有大量 IO 请求。

下一步:

  • 检查业务是不是有扫表 / 全量同步;
  • 检查应用是不是有非必要 IO(频繁写日志、无用快照);
  • 如果没有业务优化空间,考虑扩容 IOPS(云厂商)或换更高规格的盘。

9.2 await 高但 %util 不高

现象:

  • await
     持续大于 5ms
  • %util
     还不到 60%

判断:等待发生在队列层或调度器层,设备并没有真忙。

下一步:

  • 切调度器为 none 或 kyber
  • 提高队列深度 nr_requests
  • 检查是否被 cgroup blkio 限制节流;
  • 检查是否被调度器的 min_budget 类机制限制。

9.3 IO 尖刺型(业务突然卡 30 秒)

现象:

  • iostat 数据每隔几秒就出现一个尖刺;
  • 业务告警与尖刺时间对应。

常见原因:

  • 日志 rotate 触发 fsync 风暴;
  • 数据库检查点(checkpoint)刷脏页;
  • 系统 cron(如 logrotate、backup)定时触发;
  • 内核 dirty_writeback_centisecs 唤醒导致一起回写;
  • 应用层同步写远端阻塞。

下一步:

  • 查看 systemd timer、cron 调度;
  • 查看 logrotate / journald 配置;
  • 查看是否有 flock / fcntl 调用。

9.4 持续写高负载(日志型业务)

现象:

  • wkB/s
     持续在数百 MB/s;
  • 应用响应变慢。

判断:

  • 应用层的突发写;
  • 日志级别误开 debug;
  • 备份脚本写错路径。

下一步:

  • iotop
     找进程;
  • 改日志输出位置(分盘);
  • 改成异步日志(log4j/logger 加缓冲区)。

9.5 大量 random 读(数据库冷数据)

现象:

  • r/s
     高、rkB/s 大、await 高、aqu-sz 高。

判断:

  • 数据库扫描未命中索引;
  • Buffer Pool 缺失后回源到磁盘;
  • 慢查询触发全表扫。

下一步:

  • DBA 介入看慢查询;
  • 看 SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads'
  • 看应用是不是新上了聚合报表。

9.6 D 状态进程堆积

现象:

  • top
     中 wa 列升高;
  • ps -eo stat | grep D | wc -l
     > 5。

判断:

  • 大量进程阻塞在 IO;
  • 常见于 NFS 失效、磁盘坏块。

下一步:

  • cat /proc/<pid>/stack
     看内核栈;
  • df -h
     检查 NFS;
  • mount | grep nfs
     检查挂载;
  • nfsstat -m
     看 NFS 状态。

9.7 swap 引发的 IO 风暴

现象:

  • vmstat
     中 so 列不为 0;
  • iotop
     看到 kswapd0 在写。

判断:

  • 物理内存不够;
  • swappiness 过高;
  • 应用内存使用异常。

下一步:

  • 加内存;
  • 临时调 sysctl vm.swappiness=0(不能根除);
  • 优化应用内存使用。

9.8 cgroup 限制引发的 IO 节流

现象:

  • iotop
     看进程 IO 速率远低于设备能力;
  • dmesg
     / syslog 出现 cgroup blkio throttle

判断:业务在容器内或被 systemd slice 限速。

下一步:

  • systemd-cgtop
     看 slice 使用情况;
  • 调整 slice 的 IO 限制参数;
  • 观察是否需要扩容。

9.9 云服务器 IO 限速

现象:

  • 突发型云盘,积分耗尽后 IO 限速;
  • iostat
     看 wkB/s 周期性降到几十 KB/s;
  • 厂家监控对应限速告警。

判断:典型云厂商基线型 IO 限速。

下一步:

  • 升级到高 IO 规格;
  • 联系云厂商释放突发积分或开高 IO 套餐;
  • 不建议再用 fio 验证——会进一步扣积分。

9.10 RAID 卡 BBU / supercap 老化

现象:

  • 物理机 RAID 卡 BBU 失效;
  • 写性能降到十分之一;
  • megacli -LDInfo -Lall -aAll
     看 Cache policy。

判断:BBU 进入 Learn Cycle,写缓存被关闭。

下一步:

  • 改写策略为 WriteThrough 配 WriteBack 切换;
  • 备份 + 更换 BBU / supercap;
  • 联系硬件供应商。

十、风险提醒

磁盘 IO 排查涉及大量高风险操作,列出易踩的雷区。

10.1 误删磁盘上的数据

bash
# 高危:清空整块磁盘
rm -rf /var/log/*
# 危险:直接 truncate 文件
: > /var/log/messages

风险:

  • rm -rf /var/log/*
     可能误删正在打开的日志文件,导致 daemon 句柄失效;
  • :> /var/log/messages
     会把正在用的日志直接清空,可能破坏日志跟踪;
  • find -delete
     写得不对容易删错;建议在生产环境用 -print 加 -exec rm {} \; 或交互式 rm -i

替代方案:

  • 日志清理用 logrotate / journald --vacuum-time
  • 让日志旋转,不要直接 truncate;
  • 引用 find 时加 -name 和 -maxdepth 严控范围。

10.2 drop_caches 的副作用

bash
# 危险:清理页缓存
echo 3 > /proc/sys/vm/drop_caches

风险:

  • 直接清空内核页缓存,后面的所有读会回到磁盘,IO 压力瞬间爆发;
  • 已经飙升的 IO 加上突发 IO,机器可能直接卡死。

替代方案:

  • 通过 posix_fadvise(POSIX_FADV_DONTNEED) 让应用主动释放;
  • vmtouch
     工具可以精准控制某个文件的页面驻留;
  • 不要从外部强行清。

10.3 修改 dirty 参数的副作用

bash
sysctl -w vm.dirty_ratio=5

风险:

  • 把 ratio 调低会让后台回写线程长期高负载;
  • 对低内存机器上跑 Oracle、Postgres 等非常不友好;
  • 必须配合 drop_caches 谨慎使用。

替代方案:

  • 在 5.x 内核上使用 cgroup v2 的 io.weight
  • 应用层使用 fsync() 主动刷盘;
  • 监控 nr_dirty 找规律,不要无脑调小。

10.4 切换 IO 调度器风险

bash
echo none > /sys/block/sda/queue/scheduler

风险:

  • 机械盘切 none 会导致小请求雪崩;
  • SATA SSD 切 none 可能反而性能更差;
  • 切调度器本身不中断 IO,但磁盘的延迟分布瞬间变化,可能引起业务异常。

替代方案:

  • 切之前先 perf record -a -g 一段;
  • 对比 fio 测试结果;
  • 流量低的窗口操作。

10.5 cgroup 限制过严导致业务失败

bash
systemctl set-property my.service IOReadBandwidthMax=/dev/nvme0n1 100M

风险:

  • 限制过小会让业务接口超时;
  • 没有给业务感知时间,业务异常自动告警触发雪崩。

替代方案:

  • 先观察基线再设限;
  • 用 IOWeight 而非 IOReadBandwidthMax,让 qos 弹性一些;
  • 限制要可调,配合 Prometheus 告警。

10.6 在已有 IO 瓶颈的盘上跑 fio

风险:fio 本身是 IO 压力源,会让已饱和的盘雪上加霜,可能引起节点 off-line。

替代方案:

  • fio 跑在空闲盘或单独准备的盘上;
  • 用 cd /mnt/test; fio --filename=/mnt/test/io-test.bin --size=1G 不要打满整盘;
  • 不要在数据库盘上跑 fio。

10.7 误用 blktrace 阻断生产

bash
blktrace -d /dev/sda -o trace

风险:blktrace 在内核版本较老时会让 blk_remap 调用大幅增加,IO 路径上有阻塞时甚至会让机器无响应。

替代方案:

  • 用 bpftrace biosnoop 更轻量;
  • 只对单盘开启;
  • 限定采样时长。

10.8 修改内核参数导致无法启动

bash
# 假设重写 initramfs
dracut -f

风险:dracut 写错的话系统启动时会找不到 root。

替代方案:

  • 保留上一版 initramfs:用 cp /boot/initramfs-*.img /boot/initramfs-*.bak
  • dracut 完成后立即 dracut --force
  • 在测试机先验证。

10.9 修改数据库配置导致雪崩

虽然这里不展开数据库参数,但 IO 排查中也可能涉及。注意:

  • innodb_io_capacity
     调整前要先评估;
  • innodb_flush_method=O_DIRECT
     切到 O_DSYNC 可能引发脏页堆积;
  • 改动后必须看 SHOW ENGINE INNODB STATUS 的 BUFFER POOL AND MEMORY 段。

10.10 在断错盘上跑 dd

bash
ddif=/dev/zero of=/dev/sda bs=1M

风险:直接把系统盘数据清零。

替代方案:

  • 永远确认 lsblk 输出后,再用 of=/dev/<确认的设备>
  • 建议用 dd if=<file> of=/dev/null 做读测试;
  • 生产环境禁止直接对块设备写入。

十一、验证方式

排查完一项,必须知道怎么验证修复生效。下面把每条修复路径配对应的验证方法。

11.1 调度器切换验证

bash
# 切换前
cat /sys/block/sda/queue/scheduler
# [mq-deadline] bfq none

# 切换
echo bfq > /sys/block/sda/queue/scheduler

# 验证
cat /sys/block/sda/queue/scheduler
# mq-deadline [bfq] none

# 跑 fio 验证延迟
fio --name=seq --filename=/mnt/test.bin \
    --rw=read --bs=4k --size=1G --runtime=30 \
    --time_based --ioengine=libaio \
    --direct=1 --iodepth=32 --numjobs=1

判断:

  • 平均延迟下降 > 20% 视为有效;
  • 抖动 P99 下降 > 30%;
  • 与之前基线对比。

11.2 dirty 参数验证

bash
# 重启回写参数后观察
cat /proc/vmstat | grep -E 'nr_dirty|nr_writeback|nr_unstable'

判断:

  • nr_dirty
     持续保持在 10% 以下;
  • nr_writeback
     不会出现持续高位。

11.3 cgroup 限制验证

bash
systemd-cgtop
# 或
systemctl show my.service.slice -p IOReadBandwidthMax

验证:

  • 限制后业务 QoS 没有恶化;
  • 用 fio 在受限进程内跑相同负载验证。

11.4 drop_caches 修复后

仅盘可清空页缓存后用:

bash
echo 1 > /proc/sys/vm/drop_caches   # 清理页缓存
# 风险命令,仅在测试环境或业务允许的低峰期执行

风险提示:再次提醒,drop_caches 在生产环境是大杀器,会回源所有页面到磁盘,可能让数据库瞬间卡死。仅在已经做好停机计划或低峰期执行。

11.5 进程定位后的验证

  • 找到进程 → kill → 观察 IO 是否恢复;
  • kill 不可接受时 → 限速(ionice 或 cgroup);
  • 限速不可接受时 → 调整应用层(业务侧)。

11.6 业务恢复验证

业务恢复后必须:

  • 监控业务慢请求曲线;
  • 确认 IO 利用率回归基线;
  • 确认磁盘延迟回归基线;
  • 排一个回滚窗口观察(详见下一节)。

十二、回滚方案

每条修复动作必须有回滚预案。

12.1 调度器回滚

bash
# 备份当前调度器
cat /sys/block/sda/queue/scheduler > /tmp/sched.before
# 应用切调度器
echo bfq > /sys/block/sda/queue/scheduler
# 验证后落地
# 出错时:
echo $(cat /tmp/sched.before | awk -F'[][]''{print $2}') \
  > /sys/block/sda/queue/scheduler

# 持久化回滚:将 udev 规则改回
sed -i 's/ATTR{queue/scheduler}="bfq"/ATTR{queue\/scheduler}="mq-deadline"/' \
  /etc/udev/rules.d/60-io-scheduler.rules
udevadm control --reload-rules
udevadm trigger

12.2 dirty 参数回滚

bash
# 应用前快照
sysctl vm.dirty_ratio > /tmp/sysctl.dirty.bak
# 应用
sysctl -w vm.dirty_ratio=10
# 回滚
sysctl -w vm.dirty_ratio=$(cat /tmp/sysctl.dirty.bak | awk '{print $NF}')

# 持久化回滚
git -C /etc revert sysctl.d/99-io-dirty.conf --no-edit

风险提示:sysctl 即时生效,重启后通过 /etc/sysctl.d/*.conf 恢复。务必两边都改。

12.3 cgroup 限制回滚

bash
# 应用前
systemctl show my.service.slice > /tmp/slice.before
# 应用后
systemctl set-property my.service.slice IOReadBandwidthMax=/dev/nvme0n1 50M
# 回滚
systemctl revert my.service.slice
# 或
systemctl set-property my.service.slice IOReadBandwidthMax=infinity

12.4 内核参数永久化回滚

bash
# 在测试机先验证
# 回滚内核参数
sed -i 's/vm.dirty_background_ratio = 5/vm.dirty_background_ratio = 10/' /etc/sysctl.d/99-io-dirty.conf
sysctl -p /etc/sysctl.d/99-io-dirty.conf

12.5 业务层操作回滚

应用的回滚要跟随业务发布系统的能力:

  • kubectl rollout undo deployment/<dep>
    :K8s 服务回滚;
  • systemctl restart my.service
    :传统服务回滚;
  • 应用层配置回滚:跟随发布系统的 revert。

12.6 回滚窗口

生产环境所有 IO 相关修复必须配合回滚时间窗口:

  • 修复完成后挂 4-24 小时观察;
  • 关键指标(IO 利用率、P99 延迟、业务 RPS)回归基线;
  • 一旦发现新问题,立刻回滚;
  • 回滚过程同步通知业务方。

十三、生产环境注意事项

13.1 操作窗口

  • 涉及 IO 调度器、dirty 参数、cgroup 限制的改动,尽量放在业务低峰期(一般凌晨 0-6 点);
  • 大盘(如数据库)的配置变更,必须先演练;
  • 涉及内核参数的回滚脚本必须提前准备;
  • 一台一台改,不要全集群并发。

13.2 数据备份

任何 IO 相关的修复,先确认:

  • 数据库有当晚的备份;
  • 文件系统能用 xfsdump / ext4 snapshot 备份;
  • fio
     测试文件单独创建,不影响业务。

13.3 监控与告警

修复期间必须额外盯:

  • iostat 类的 await / aqu-sz / %util
  • 业务 RPS / P99 延迟;
  • 错误率(如数据库 Error 1290 之类);
  • PSI some 指标。

13.4 灰度与金丝雀

  • 单台机器先改;
  • 观察 30 分钟到 2 小时;
  • 同样的机器型号批次先改一台;
  • 没问题再扫全集群。

13.5 沟通与文档

  • 修复开始前通知业务方、值班、DBA、SRE;
  • 在工单或变更单里写明变更原因、操作、风险、回滚步骤;
  • 修复后做事故复盘,写入故障复盘文档。

13.6 与数据库团队的协作

数据库盘的 IO 改动必须和 DBA 协同:

  • ALTER TABLE
     大表的 IO 行为需要 DBA 在场;
  • OPTIMIZE TABLE
     / ALTER TABLE ... ENGINE=InnoDB 是 IO 大户;
  • 在线 DDL 工具(如 gh-ost)需要 DBA 评估。

13.7 云环境额外注意

  • 云盘的 IOPS 会被突发的 burst 限制,运维操作要用 fio 测时把 burst 留着;
  • 云盘的快照要避免在 IO 高峰进行;
  • 跨可用区的 IO 链路延迟比本机差,要重新算 IO 阈值;
  • 公有云控制台和实机看到的 IO 指标有时差距,要以 node_exporter 数据为准。

13.8 容器云环境

  • 容器内的 iotop / pidstat 不再准确(看到的 cgroup 视图);
  • 在宿主机上抓 docker top <container> 即可看到容器主进程;
  • 共享同一卷的容器会争抢 IO;
  • Kubernetes volume.beta.kubernetes.io/mount-options 永久设置调度器,但只对新挂载生效。

十四、总结

磁盘 IO 排查是工程实战的硬功夫。把上面的步骤收一收,按三层深度的顺序总结:

  1. 从现象出发
    :明确是 top 上的 wa 还是 iostat 上的 await,先确认 IO 是不是主导。
  2. 从全局到进程
    :先 iostat 看盘,再 iotop / pidstat 找进程,最后 lsof 找文件。
  3. 从进程到内核
    :从进程的 IO 栈往内核栈看,必要时打开 blktrace / bpftrace
  4. 从内核到硬件
    :dmesg、SMART、RAID 卡、BIOS 固件版本逐层验证。
  5. 修复后再验证
    :调度器切换、dirty 参数调整、cgroup 限制修改都必须配合回滚与监控。
  6. 生产纪律
    :备份先行、灰度推开、回滚预案、沟通同步、复盘归纳。

最后再强调一次雷区:

  • drop_caches
     在生产勿用;
  • rm -rf
     不要随便写通配;
  • 切调度器之前先量基线;
  • fio
     跑错盘直接数据库雪崩;
  • 内存不够的机器上 sysctl 救不了,盘才是源头。

把上面的命令、配置、决策树放在自己工位的备忘录里,再遇到 iostat 飙红就不用慌。

文末福利

今天给大家分享一份超级牛掰的Linux学习笔记,足足有1456页!是一位Linux运维大佬整理分享的,分享是获得大佬同意的,大家有需要的尽管收藏起来!

笔记介绍

这份笔记非常全面且详细,从Linux基础到shell脚本,再到防火墙、数据库、日志服务管理、Nginx、高可用集群、Redis、虚拟化、Docker等等,与其说Linux学习笔记,不如说是涵盖了运维各个核心知识。

并且图文并茂,代码清晰,每一章下面都有更具体详细的内容,十分适合Linux运维学习参考!

笔记展示

笔记下载

扫描下方二维码,回复暗号1456页Linux笔记“,即可100%免费领取成功

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 09:45:07 HTTP/2.0 GET : https://f.mffb.com.cn/a/503137.html
  2. 运行时间 : 0.166443s [ 吞吐率:6.01req/s ] 内存消耗:4,760.31kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=f61532a6550eaea74877d87bbfd50e76
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000716s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000791s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.003685s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.010493s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000690s ]
  6. SELECT * FROM `set` [ RunTime:0.006764s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000768s ]
  8. SELECT * FROM `article` WHERE `id` = 503137 LIMIT 1 [ RunTime:0.012485s ]
  9. UPDATE `article` SET `lasttime` = 1783043107 WHERE `id` = 503137 [ RunTime:0.031931s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.002443s ]
  11. SELECT * FROM `article` WHERE `id` < 503137 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000553s ]
  12. SELECT * FROM `article` WHERE `id` > 503137 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003435s ]
  13. SELECT * FROM `article` WHERE `id` < 503137 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005300s ]
  14. SELECT * FROM `article` WHERE `id` < 503137 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.010720s ]
  15. SELECT * FROM `article` WHERE `id` < 503137 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.006273s ]
0.168112s