★ redo log、undo log、binlog 分别管什么?两阶段提交解决什么问题?
结论先行:undo log 记录如何撤销(回滚与 MVCC),redo log 记录如何重做(InnoDB 崩溃恢复),binlog 是 MySQL Server 层的逻辑日志(主从复制与时间点恢复)。redo 与 binlog 分属不同组件,为让两者一致,InnoDB 采用“redo prepare → 写 binlog → redo commit”的两阶段提交。
一、三类日志对比
| 对比项 | redo log | undo log | binlog |
|---|---|---|---|
| 所在层 | InnoDB 存储引擎 | InnoDB 存储引擎 | MySQL Server 层 |
| 记录内容 | 物理页的修改 | 行的旧版本(逆操作) | 逻辑 SQL/行变更 |
| 核心作用 | 崩溃恢复、持久性 | 回滚事务、MVCC 版本链 | 主从复制、恢复、审计 |
| 记录时机 | 每次修改先写 | 事务内修改前写 | 事务提交时写 |
| 文件示例 | ib_logfile0/1 | undo 表空间 | mysql-bin.000001 |
二、一条 UPDATE 的写入顺序
1. 读数据页到内存,修改前写 undo(留旧版本)
2. 写 redo log,状态 prepare,同时改内存页
3. 写 binlog
4. 把 redo log 状态改为 commit,事务提交
三、两阶段提交解决了什么
- 崩溃可能发生在任意一步,会出现“redo 有但 binlog 没有”或相反,导致主从数据不一致。
- 两阶段提交让 redo 与 binlog 以同一事务 id 对账:恢复时两边都落盘才生效,否则回滚丢弃。
- 对账规则:redo 是 prepare 且 binlog 已落 → 事务补提交;否则回滚,保证崩溃后主从一致。
四、刷盘参数(双 1)
innodb_flush_log_at_trx_commit = 1 -- 每次提交都刷 redo,最安全
sync_binlog = 1 -- 每次提交都刷 binlog
常见追问与记忆点
- 追问:为什么不能让 binlog 先写?binlog 没有崩溃恢复能力,必须以 InnoDB 的 redo 为最终裁决者。
- 追问:group commit 是什么?多个事务的提交刷盘合并为一次 fsync,提升吞吐。
- 追问:binlog 的 row 格式与两阶段提交的关系?row 格式记录行级变更,配合两阶段对账,是恢复与校验的基础。
- 记忆点:undo 管回滚、redo 管恢复、binlog 管复制;prepare 与 commit 之间夹着 binlog 就是两阶段提交。