mysql事务提交时仅强制刷redolog(默认innodb_flush_log_at_trx_commit=1),undolog可延迟刷盘;因undolog用于回滚和mvcc而非已提交事务持久性,其刷盘由purge thread异步处理,崩溃恢复时通过redolog重建undo页。

事务提交时,MySQL 真正刷了哪些日志?
事务 COMMIT 执行成功,并不意味着数据页已落盘。它只代表 MySQL 认为这组变更“逻辑上已完成”,后续由后台线程异步保障持久性。关键在于:UndoLog 和 RedoLog 的写入时机与作用完全不同——RedoLog 必须在 COMMIT 返回前刷盘(默认 innodb_flush_log_at_trx_commit=1),而 UndoLog 只需写入内存(undo log buffer),甚至可延迟刷到 undo 表空间。
UndoLog 为什么不需要在 COMMIT 时强制刷盘?
UndoLog 的核心职责是支撑回滚(ROLLBACK)和 MVCC 快照读,不是保证已提交事务的持久性。一旦事务提交,对应 UndoLog 就进入“可清理”状态(标记为 TRX_UNDO_CACHED 或转入 history list),后续由 Purge Thread 异步回收。若此时崩溃,已提交事务的数据变更靠 RedoLog 恢复;未提交事务则用 UndoLog 回滚——但该 UndoLog 是否在磁盘上,不影响恢复逻辑,因为 InnoDB 在崩溃恢复阶段会从 RedoLog 中重建活跃事务列表,并关联其 UndoLog 段(只要 Undo page 还在 buffer pool 或能从磁盘读取即可)。
- UndoLog 写入磁盘是 lazy 的,受
innodb_max_undo_log_size和 purge 进度驱动 - 即使 UndoLog page 还在 buffer pool 里没刷盘,崩溃后也能通过 RedoLog 把这些 page 重新载入并用于回滚
- 强制让 UndoLog 同步刷盘会显著拖慢提交性能,且无实际收益
RedoLog 刷盘策略如何影响 COMMIT 延迟?
innodb_flush_log_at_trx_commit 是决定 COMMIT 是否“真正持久”的开关:
-
1(默认):每次COMMIT都调用fsync()刷 RedoLog 文件,最安全,但延迟最高 -
0:事务提交时不刷盘,依赖后台每秒一次log_write_up_to(),崩溃可能丢一秒事务 -
2:只写 OS page cache(write()),不fsync(),依赖 OS 刷盘,崩溃可能丢少量事务(通常
注意:COMMIT 的耗时主要卡在 fsync() 上——尤其是机械盘或高负载 SSD。若观察到 COMMIT 平均耗时突增,先查 RedoLog 所在磁盘 I/O 延迟,再确认该参数值。
崩溃恢复时 UndoLog 和 RedoLog 怎么配合?
MySQL 启动时执行 crash recovery,流程不是“先重放 RedoLog,再应用 UndoLog”,而是分两阶段:
-
分析阶段(Analysis):扫描 RedoLog,构建
redo log checkpoint之后的 active transaction table(哪些事务没 commit / rollback) - 重做阶段(Redo):按 RedoLog 序列重放所有已提交事务的物理变更(包括数据页、undo page、系统表等)
- 回滚阶段(Undo):对 Analysis 阶段识别出的未完成事务,用其对应的 UndoLog 回滚(即反向执行)
这里的关键是:RedoLog 重做的不只是用户数据页,还包括 undo page 本身。所以即使崩溃前 UndoLog 还没刷盘,只要 RedoLog 覆盖了它的修改,恢复时就能把 undo page 重建出来,再用于回滚。这也是为什么 RedoLog 必须在 COMMIT 前刷盘——它要兜底整个恢复链路。
真正容易被忽略的是:UndoLog 的物理结构(如 TRX_UNDO_INSERT 段)本身也受 RedoLog 保护,而它的生命周期管理(分配、截断、purge)全靠 RedoLog 串起来。没有 RedoLog,UndoLog 就是一堆无法自洽的碎片。











