redo log切换频繁导致写入链路卡死而非变慢;write_pos追上checkpoint时强制停写刷脏页,引发com_commit骤降、innodb_os_log_pending_fsyncs飙升、线程卡在query end状态。

Redo Log切换频繁直接导致写入链路被强制中断,不是慢,是卡死。
Redo Log切换时会发生什么硬阻塞
InnoDB用Redo Log做WAL,但日志空间是环形的。一旦write_pos追上checkpoint位置,就必须停掉所有新事务、强制刷脏页腾出空间——这个过程不接受任何写入请求。
- 现象是
Com_commit骤降、Innodb_os_log_pending_fsyncs飙升、SHOW PROCESSLIST里大量线程卡在query end状态 - 不是磁盘慢,是InnoDB主动“踩刹车”:它宁可停写,也不覆盖未刷盘的脏页对应的日志
- 每分钟切一次,等于每分钟强制卡住写链路一次;切得越勤,抖动越密,QPS曲线像心电图
怎么确认是不是Redo Log切换惹的祸
别猜,看三个硬指标:
- 查日志文件修改时间:
ls -lt /var/lib/mysql/ib_logfile*,相邻文件最后修改时间差若常低于5分钟,基本坐实 - 看
SHOW ENGINE INNODB STATUS\G里的LOG段:Log sequence number和Last checkpoint at差值长期逼近innodb_log_file_size × innodb_log_files_in_group - 监控
Innodb_log_waits持续上升,说明事务在等日志空间释放
为什么调大innodb_log_file_size比调其他参数更治本
根本矛盾是“日志写得太快,脏页刷得太慢”。扩大单个日志文件,等于拉长两次checkpoint的时间窗口,让刷脏页调度更平滑。
- 默认48MB × 2 = 96MB总容量,在120 MB/s写入压力下,30秒就满——必须每半分钟卡一次
- 设为1GB × 3 = 3GB后,同样压力下可撑25分钟以上,checkpoint从“硬触发”变成“软调度”
- 注意:
innodb_log_file_size必须是512KB整数倍;改完不删旧ib_logfile*,MySQL启动直接报InnoDB: Error: log file ./ib_logfile0 is of different size
容易被忽略的协同陷阱
光调大日志文件不够,还得防配套机制反向拖垮效果:
-
innodb_flush_log_at_trx_commit = 1+sync_binlog = 1组合会触发两次fsync,I/O翻倍,日志再大也扛不住 - 把
ib_logfile*和数据文件放在同一块HDD上,刷日志和刷脏页抢同一个磁头,顺序写退化成随机IO -
innodb_log_buffer_size太小(如默认16MB)会导致高并发小事务每秒刷多次buffer,日志文件再大也救不了buffer层瓶颈
真正卡点从来不在单一参数,而在write_pos、checkpoint、刷盘线程、磁盘调度这四者的咬合时机——差100ms,就是抖一下;差1秒,就是挂5分钟。











