用 iotop -p $(pgrep mysqld) -h -o -d 1 可精准定位 mysqld 内高 io 线程,如 log_writer、purge_thread;结合 show engine innodb status 中 file i/o 和 log 段的 pending i/o、lsn 与 checkpoint 差值,以及 lsof 输出的频繁读写文件,可确认真实瓶颈源。

用 iotop 看清 mysqld 进程里谁在疯狂读写
iotop 不是看“哪个进程”,而是看“哪个线程”——MySQL 的每个内部操作(如刷脏页、写 redo、purge、read-ahead)都以独立线程运行,iotop -p $(pgrep mysqld) 能直接暴露它们的实时 I/O 量。默认只显示进程级汇总,必须加 -H(显示线程)和 -o(只显示有 I/O 的线程),否则你会漏掉真正肇事者。
-
iotop -p $(pgrep mysqld) -H -o -d 1:每秒刷新,聚焦活跃线程 - 关注
IO>列值高的线程,结合TID和COMMAND判断角色 - 常见高 IO 线程名包括:
mysqld -- io_write_thread、mysqld -- log_writer、mysqld -- purge_thread、mysqld -- read_ahead - 若看到大量
pwrite64+ib_logfile0,说明 redo log 写入压力大;若pread64频繁读xxx.ibd,可能是全表扫描或 buffer pool 太小
SHOW ENGINE INNODB STATUS\G 里的 FILE I/O 和 LOG 部分不能跳过
FILE I/O 段告诉你 InnoDB 后台线程是否被 I/O 卡住:pending reads 或 pending writes 非零,代表磁盘响应跟不上请求节奏;LOG 段里 Log sequence number 和 Last checkpoint at 差距过大(比如超 1GB),说明 checkpoint 落后,会触发批量刷脏页,瞬间推高磁盘写。
-
Pending normal aio reads: 0是理想状态;若持续 >5,配合iotop中io_read_thread高 IO,基本确认是物理读瓶颈 -
Log flushed up to和Last checkpoint at差值超过innodb_log_file_size × 2,大概率引发突发写压力 - 注意
UNDO LOG段里History list length:若 >100000,purge 线程追不上,会持续读写ibdata1或 undo 表空间文件
为什么 iostat -x 1 显示 %util 高,但 slow_query_log 里没几条慢 SQL
因为高磁盘 IO 不一定来自用户 SQL。InnoDB 主动行为(如脏页刷盘、log writer 批量落盘、purge 清理、read-ahead 预读)会占用 I/O 带宽,却不记录进慢日志。这时 iostat 的 w/s 和 r/s 会突增,但 SHOW GLOBAL STATUS LIKE 'Innodb_data_writes' 可能平稳,而 SHOW GLOBAL STATUS LIKE 'Innodb_log_writes' 或 Innodb_os_log_written 才真正飙升。
- 先对比:
Innodb_log_writes每秒是否 >1000?若是,log_writer线程就是主力 - 再查:
Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total是否 >15%?过高说明刷盘压力被动堆积 - 最后验证:
innodb_io_capacity设置是否远低于磁盘真实 IOPS(如 NVMe 实测 50000,却设为 2000),这会导致 InnoDB 主动限速失败,转而靠队列堆积释放压力
别忽略 lsof -p $(pgrep mysqld) 和文件状态的对应关系
lsof 能把线程级 I/O 行为落到具体文件上。重点关注 TYPE=REG(普通文件)、FD=W(写打开)或 FD=DEL(已删除但句柄仍打开,常见于轮转中的 binlog 或 redo log)的行。如果某 .ibd 文件反复出现在高 IO 线程的 lsof 输出里,且 iostat 显示该设备 %util 高,那它就是热点数据文件——但注意,若 innodb_file_per_table=OFF,所有表都挤在 ibdata1,这时无法按表归因,只能整体优化。
-
lsof -p $(pgrep mysqld) | awk '$5=="REG" && ($4~"w" || $4~"DEL") {print $9}' | sort | uniq -c | sort -nr:快速统计哪些文件被频繁写 - 若输出含大量
/var/lib/mysql/ib_logfile,优先检查innodb_flush_log_at_trx_commit和sync_binlog配置 - 若大量
/var/lib/mysql/mysql-bin.出现,确认 binlog 是否与数据文件共盘,以及是否启用了binlog_group_commit_sync_delay
真实瓶颈常藏在线程与文件的交叉点:一个 log_writer 线程持续写 ib_logfile0,同时 purge_thread 在读 ibdata1,而这两者又共享同一块 NVMe 设备——这时候调参数不如挪文件。











