redo log是InnoDB实现崩溃恢复的核心,记录物理逻辑日志,循环写入固定大小文件,事务提交时只需redo log落盘即可保证持久性,崩溃后通过重放未checkpoint日志恢复数据。

事务日志(redo log)是 InnoDB 实现崩溃恢复的核心
InnoDB 不靠 binlog 做崩溃恢复,真正保证事务持久性(DURABLE)的是 redo log。它记录的是「物理逻辑日志」——不是 SQL 语句,也不是最终数据页的完整镜像,而是「对某个表空间第 X 页的第 Y 个槽位执行了 Z 类型修改」这类操作。这种设计兼顾了写入效率和恢复精度。
关键点:
-
redo log是循环写入的固定大小文件(默认ib_logfile0、ib_logfile1,各 48MB),写满后从头覆盖,所以它只保留最近足够恢复的变更 - 事务提交时,只要
redo log写入磁盘(由innodb_flush_log_at_trx_commit控制),就算成功;此时对应的数据页可能还在 Buffer Pool 里没刷盘(lazy write) - MySQL 崩溃重启后,InnoDB 会重放
redo log中未 checkpoint 的部分,把已提交但未落盘的数据页“追回来”
为什么不能只靠 Buffer Pool 落盘来保证持久性
因为 Buffer Pool 是内存结构,断电即丢。如果等每个事务都把修改后的数据页刷到磁盘(即同步写 data file),性能会暴跌——随机 IO 变成强制瓶颈。而 redo log 是顺序追加写,可批量合并、缓存优化,延迟刷盘也不影响 ACID 中的 D(持久性)。
典型错误理解:
- 认为
SET autocommit=1后就“自动刷盘”,其实只是自动提交事务,redo log是否落盘仍取决于innodb_flush_log_at_trx_commit - 把
binlog当作事务日志:binlog 是 Server 层日志,用于主从复制和 PITR(基于时间点恢复),不参与崩溃恢复;InnoDB 恢复完全不依赖 binlog - 误删
ib_logfile*文件后直接启动 MySQL:会导致 recovery 失败或数据不一致,必须先关闭 MySQL,清空日志并让 InnoDB 重建(需确保 shutdown 是 clean 的)
如何查看和调优 redo log 相关配置
运行时可通过 SHOW VARIABLES LIKE 'innodb_log%' 查看关键参数,其中最常调的是:
-
innodb_log_file_size:单个 redo log 文件大小。增大可减少 checkpoint 频率,降低写放大,但也会延长崩溃恢复时间(需重放更多日志) -
innodb_log_group_home_dir:redo log 文件所在目录,默认是数据目录,建议与 data file 分盘存放以避免 IO 竞争 -
innodb_log_buffer_size:Log Buffer 大小,默认 16MB。大事务(如大批量 INSERT)容易填满它,触发提前刷盘;可适当调高,但没必要超过 64MB -
innodb_flush_log_at_trx_commit:取值 0/1/2。1 是默认且最安全(每次 commit 都 fsync 到磁盘);0 和 2 有丢事务风险,仅限可接受秒级数据丢失的场景
注意:innodb_log_file_size 修改需停机,删除旧文件前必须确保 MySQL 正常 shutdown(否则 ib_logfile* 可能含未 checkpoint 数据)。
undo log 和 redo log 的分工容易混淆
两者都在 ibdata1(或独立 undo tablespace)里管理,但作用完全不同:
-
redo log保证已提交事务的持久性(crash safe) -
undo log保证事务的原子性和一致性(rollback + MVCC),它存的是「反向操作」,比如 INSERT 对应 DELETE,UPDATE 记录旧值 - 一个事务的
undo log在提交后不会立即清除,要等所有快照读(READ COMMITTED / REPEATABLE READ)都不再需要它时,才由 purge 线程异步清理 - 如果长事务不提交,
undo log一直保留,可能导致ibdata1持续膨胀,甚至阻塞 purge,最终拖慢整个实例
真正难调试的,往往是 undo log 积压引发的锁等待、history list length 过长、purge lag,而不是 redo log 本身。但很多人一看到“日志”就只盯着 ib_logfile* 看。










