MySQL Undo Log vs Redo Log
mysql数据库如何实现数据一致性(崩溃异常情况下数据不丢失), redo + undo来保证。
1.MySQL Undo Log vs Redo Log
在 InnoDB 存储引擎中:
Undo Log(回滚日志)
解决:- 事务回滚(Rollback)
- MVCC(多版本并发控制)
- 一致性读(快照读)
Redo Log(重做日志)
解决:- 崩溃恢复(Crash Recovery)
- 持久化(Durability)
- WAL(Write Ahead Logging)
二者属于 InnoDB 事务系统的核心。
2.核心区别
| 对比项 | Undo Log | Redo Log |
|---|---|---|
| 中文 | 回滚日志 | 重做日志 |
| 作用 | 撤销数据 | 重做数据 |
| 方向 | 逻辑逆操作 | 物理页修改 |
| 用途 | 回滚/MVCC | 崩溃恢复 |
| 生命周期 | 事务结束后可清理 | checkpoint后可覆盖 |
| 存储内容 | 修改前数据 | 修改后页变更 |
| 是否持久化 | 是 | 是 |
| 属于 | 事务层 | 存储引擎恢复层 |
| 是否用于MVCC | 是 | 否 |
| 是否提升写性能 | 间接 | 直接核心作用 |
3.Undo Log 工作机制
3.1 本质
Undo Log 保存:数据修改之前的旧版本。
例如:
1 | UPDATE user SET age=20 WHERE id=1; |
修改前:
1 | age=18 |
Undo 中记录:把 age 从20恢复成18
3.2 回滚流程(undo log)
事务:
1 | BEGIN; |
回滚时:
1 | Undo Log: |
InnoDB 根据 undo 反向恢复数据。
3.3 MVCC核心
Undo Log 还承担:
快照读
事务A:
1 | BEGIN; |
事务B:
1 | UPDATE user SET age=30; |
事务A依然可能读到旧数据。
原因:
1 | 旧版本保存在 Undo Log |
MVCC链:
1 | 最新行 |
4.Redo Log 工作机制
4.1 本质
Redo Log 保存:页修改操作不是SQL。
例如:
1 | UPDATE user SET age=20 WHERE id=1; |
Redo可能记录:
1 | page 10 offset 200: |
属于物理日志。
4.2 为什么需要Redo
如果每次事务提交都:
1 | 直接刷磁盘数据页 |
代价极大:
- 随机IO
- 数据页16KB
- 磁盘寻址慢
因此 InnoDB WAL机制(Write Ahead Logging)
流程:
1 | 先写 redo log |
因为 redo log:
- 顺序写
- append写
- 非常快
5.Redo Crash Recovery
5.1 崩溃场景
事务:
1 | COMMIT; |
此时:
1 | redo已落盘 |
机器断电。
5.2 启动恢复
MySQL 重启:扫描 redo log,重新执行页修改恢复数据。这就是:crash-safe
6.Undo 与 Redo协同
真正事务提交流程:
flowchart LR A[修改Buffer Pool] --> B[记录Undo] B --> C[记录Redo] C --> D[提交事务] D --> E[Redo fsync] E --> F[后台刷脏页]
7.为什么两种日志都必须存在
7.1 只有Redo不行
无法:
- 回滚
- MVCC
- 快照读
因为 redo 只有“怎么改”。没有“改之前是什么”。
7.2 只有Undo不行
无法:
- 崩溃恢复
- 保证持久化
因为:内存脏页可能没落盘,数据库重启后数据丢失。
8.事务提交全过程(核心)
事务:
1 | BEGIN; |
执行过程:
Step1 修改Buffer Pool
内存页修改:
1 | 18 -> 20 |
Step2 写Undo(修改前数据)
记录:
1 | 20 -> 18 |
Step3 写Redo Buffer
记录:
1 | page修改 |
Step4 COMMIT
触发:
1 | redo buffer -> redo file |
fsync。
Step5 返回客户端成功
此时:
即使机器断电:
1 | redo仍能恢复 |
Step6 后台Checkpoint
异步刷:
1 | 脏页 -> ibd文件 |
9.对应磁盘文件
9.1 Undo
MySQL 8:
1 | undo tablespace |
文件:
1 | undo_001 |
或者:
1 | ibdata1 |
历史版本。
9.2 Redo
文件:
1 | #innodb_redo/ |
MySQL 8 新格式。
旧版本:
1 | ib_logfile0 |