RedoLog写满导致Checkpoint强制推进会阻塞所有更新,引发MySQL瞬间抖动甚至假死;表现为Threads_running骤降为0、Innodb_buffer_pool_pages_dirty断崖式下降,且刷盘过程同步阻塞DML。

因为 Checkpoint 推进时触发的脏页刷盘(flush)会集中消耗 I/O 和 CPU,且某些场景下会阻塞更新线程。
redo log 写满强制推进 checkpoint 会完全卡住写入
这是最典型的“掉速”甚至“假死”原因:当 write pos 追上 checkpoint,redo log 环形缓冲区无空闲空间,InnoDB 必须立刻把 checkpoint → write pos 区间对应的所有脏页刷到磁盘,才能腾出日志空间。这个过程不是渐进的,而是同步阻塞型的:
- 所有 DML(
INSERT/UPDATE/DELETE)会被挂起,innodb_row_lock_waits可能飙升 - 监控上看:
Threads_running突降为 0,Innodb_buffer_pool_pages_dirty断崖式下降,但磁盘%util不一定高(因为刷的是冷页或压缩页,I/O 吞吐未必打满) - 错误日志里不会报错,但你能看到类似
Waiting for query cache lock或长时间updating or deleting的线程状态 - 该行为与
innodb_fast_shutdown无关,是运行时硬性保护机制
fuzzy checkpoint 在后台刷脏页也可能引发抖动
MySQL 5.6+ 默认只用 fuzzy checkpoint,但它仍可能在不合适的时间点集中刷页,尤其当配置失当时:
-
innodb_io_capacity设得太低(如默认 200),而实际磁盘 IOPS 能到 3000+,会导致脏页积压,然后某次page cleaner线程爆发式刷出数百页 -
innodb_max_dirty_pages_pct设为 90(默认值),意味着 Buffer Pool 90% 都是脏页才开始主动刷——这已经非常危险,稍有并发写入就容易触达临界点 - 当
FLUSH_LRU_LIST触发时(例如 LRU 空闲页不足),它会优先刷最老的脏页,但这些页可能刚被修改过,导致重复刷盘(page re-dirty) - 如果你开了
innodb_flush_neighbors=1(默认),一次刷页会连带刷相邻物理页,放大 I/O 放大效应,在 SSD 上反而降低效率
如何确认是不是 checkpoint 导致的抖动
别猜,直接查 InnoDB 实时状态和历史趋势:
- 执行
SHOW ENGINE INNODB STATUS\G,重点关注LOG小节里的Log sequence number和Last checkpoint at差值——如果差值接近innodb_log_file_size × 2(即整个 redo log 容量),说明快满了 - 观察
innodb_buffer_pool_pages_dirty和innodb_buffer_pool_pages_flushed每秒增量:如果后者突增 1000+,同时前者断崖下跌,基本就是 checkpoint 刷盘在发力 - 用
pt-stalk或sys.schema_table_statistics抓取抖动瞬间的trx_state和等待事件,wait/io/file/innodb/innodb_data_file高占比是铁证 - 检查
innodb_adaptive_flushing是否开启(MySQL 5.6+ 默认 ON):关掉它有时反而更稳,因为自适应算法在负载突变时容易误判
真正麻烦的不是 checkpoint 本身,而是它暴露了底层配置和负载节奏的不匹配——比如 buffer pool 太小却扛着高更新量,或者 redo log 文件太小还用了默认 48MB。这些细节在压力平稳时藏得住,一到业务高峰就全冒出来。


















