MySQL崩溃恢复必须扫描Redo日志,因为已提交但未刷盘的事务变更仅存于Redo日志中;InnoDB需从last_checkpoint_lsn开始逐条解析物理操作,以重做脏页,否则将静默丢失数据。

因为崩溃时未刷盘的已提交事务变更,只存在于Redo Log里——不扫描它,就根本不知道该重做哪些页、哪些偏移、哪些值。
崩溃后数据页和内存状态都是“残缺”的
MySQL运行时,UPDATE或INSERT先改Buffer Pool中的页(变脏页),再记redo log,但不会立刻写磁盘数据文件(.ibd)。一旦kill -9或断电,Buffer Pool全丢,.ibd里还是旧内容。唯一保留“这次提交到底干了什么”的,只有磁盘上的ib_logfile0和ib_logfile1。
- 不扫描
redo log,InnoDB 启动时连“哪些页被改过”都不知道,更别说恢复 - 哪怕只差 1 个字节没刷盘,整个 16KB 页就处于“旧状态”,必须靠日志补全
- 扫描不是读一遍完事,而是按
LSN顺序逐条解析物理操作:比如“页号 1234,偏移 56,写入 4 字节 0xABCDEF00”
Checkpoint 决定了扫描起点,不是跳过扫描的理由
last_checkpoint_lsn存于ib_logfile0前几个 block,它标记的是“这个 LSN 之前的所有变更,对应的数据页已确认刷盘”。但它不等于“不用扫描”,而是告诉 InnoDB:从这个 LSN 开始往后扫,别往前翻旧日志。
- 如果误以为 checkpoint = 恢复完成,直接跳过扫描,就会漏掉 checkpoint 之后、崩溃之前已提交但未刷盘的全部变更
- checkpoint 是动态推进的,可能刚推进一半就崩了——所以每次启动都必须重新定位并扫描
- 日志文件是循环写(
ib_logfile0 → ib_logfile1 → ib_logfile0…),不扫描就无法判断当前有效日志边界
不扫描 Redo Log 的后果是“自动静默丢数据”
MySQL 启动时若发现ib_logfile*存在且非空,一定会触发 recovery 流程;但如果因配置错误(如innodb_force_recovery > 0)或权限问题导致扫描失败,InnoDB 可能跳过 redo 应用,直接加载数据字典——此时你查不到刚提交的行,也不会报错,就像那条事务从未发生过。
- 典型现象:
SHOW ENGINE INNODB STATUS\G中LOG小节的Log sequence number和Log flushed up to差距极大,但启动日志里没有Doing recovery - 错误配置如
innodb_log_file_size被手动删文件后未重置,会导致日志头解析失败,扫描中止 - 底层存储设备禁用
fsync(如某些云盘挂载选项为barrier=0),可能导致日志文件本身损坏,扫描到坏块就卡住
真正容易被忽略的一点是:扫描 Redo Log 不是“选做题”,它是崩溃恢复不可绕过的物理前提——哪怕你的业务逻辑再简单,只要用了 InnoDB,只要事务提交过,就必须走这一遍。跳过它,持久性承诺就彻底失效。


















