iostat显示%util>80%且w_await>20ms、iotop中mysqld io飙升时,可确认磁盘i/o已成瓶颈;需结合w_await与svctm差值、avgqu-sz及wkb/s联动分析,避免单看%util误判。

MySQL查询慢不一定是文件系统IO问题,但当iostat显示%util持续 > 80% 且 w_await > 20ms,同时iotop里看到mysqld进程的IO>列频繁飙高,那基本可以锁定是磁盘I/O成了瓶颈——不是“可能”,而是“正在发生”。
怎么看iostat输出里哪些字段真有用
别只扫一眼%util就下结论。这个值在NVMe或现代多队列SSD上早已失真,100% util可能只对应30%物理吞吐能力。关键要看三组联动指标:
-
w_await和svctm的差值:如果w_await=92而svctm=0.3,说明写请求卡在队列里,不是磁盘慢,是上层压得太猛 -
avgqu-sz是否持续 > 1:>5 就值得警惕,>10 基本确认队列积压,尤其配合高w_await -
wkB/s对比设备标称吞吐:比如wkB/s才 20MB/s 但w_await已破 50ms,说明不是带宽打满,而是小IO+同步刷盘(如innodb_flush_log_at_trx_commit=1+sync_binlog=1)拖垮了响应
iotop里怎么快速揪出MySQL的IO元凶
sudo iotop -o能过滤掉静默进程,但mysqld常以多个线程形式出现,光看进程名容易漏掉真正干活的线程。实操要点:
- 按
P键按IO速率排序,盯住TID列——MySQL后台线程(如io_write_thread、log_writer_thread)常比主进程mysqld本身IO更高 - 用
sudo iotop -p $(pgrep mysqld | tr '\n' ',' | sed 's/,$//')把所有MySQL相关TID一次性过滤出来 - 若发现某线程
IO>长期 > 90%,但COMMAND显示为[jbd2/sda1-8]这类内核线程,说明是ext4日志提交在阻塞,不是MySQL代码问题,而是文件系统层配置(如挂载参数data=ordered)或磁盘响应延迟
为什么df和lsof必须跟在iostat+iotop后面查
当iostat指向/dev/sda、iotop确认是mysqld在写,但df -h发现/var/lib/mysql所在分区使用率才 60%,这时别急着调优SQL——先跑这三行:
sudo lsof +D /var/lib/mysql 2>/dev/null | awk '$5 ~ /^REG/ && $9 ~ /\.ibd|\.log$/' | head -10
sudo cat /proc/$(pgrep mysqld)/stack | grep -E "(write|fsync|sync_file_range)"
find /var/lib/mysql -name "*.ibd" -size +500M -exec ls -lh {} \; 2>/dev/null | sort -k5 -hr | head -3
常见陷阱:
-
lsof +D默认不递归子目录,innodb_file_per_table=ON时每个表一个.ibd,得加-R参数(但开销大,慎用) -
/proc/PID/stack能暴露MySQL是否卡在fsync系统调用上——如果是,sync_binlog或innodb_flush_method(比如设成O_DIRECT但底层存储不支持)就是根因 - 大
.ibd文件本身不等于高IO,但若find结果里全是最近1小时内修改的,结合业务时间点,大概率是某张表被高频INSERT ... ON DUPLICATE KEY UPDATE反复刷脏页
最易被忽略的是:MySQL的IO压力未必来自SQL执行,而可能来自后台线程的隐式行为——比如innodb_buffer_pool_size过小导致频繁刷脏页,或log_bin开启后binlog cache频繁落盘。这些不会在慢查询日志里留下痕迹,但iostat和iotop会诚实反映。盯着指标看,比猜配置更可靠。











