外观
一句话答案
MySQL 用两阶段提交保证 redo log 和 binlog 一致:redo prepare→写 binlog→redo commit,崩溃时据此判断提交或回滚。
核心要点
为什么需要两阶段提交?
如果 redo log 和 binlog 不协调提交,会出现数据不一致:
- 先写 redo log,宕机,binlog 没写:主库重启后数据有,但备库没同步,主从不一致
- 先写 binlog,宕机,redo log 没写:binlog 有记录,但主库重启后数据丢失,主从不一致
两阶段提交流程(InnoDB + MySQL Server 协调):
事务提交过程:
Phase 1(Prepare 阶段):
1. InnoDB 将 redo log 写入,状态标记为 prepare
2. redo log 刷盘(fsync)
Phase 2(Commit 阶段):
3. MySQL Server 将 binlog 写入并刷盘(fsync)
4. InnoDB 将 redo log 状态从 prepare 改为 commit
崩溃恢复逻辑:
宕机重启后扫描 redo log:
├─ redo log 状态为 commit → 事务已完成,无需处理
├─ redo log 为 prepare,且 binlog 中有对应事务记录 → 补全 commit,提交事务
└─ redo log 为 prepare,但 binlog 中无记录 → 回滚事务这样保证了 redo log 和 binlog 的最终一致性。
四、性能优化
追问与易错
追问方向:
- 两阶段提交性能开销在哪?
- 组提交是什么?
- redo log 写满了会怎样?
易错点:
- ❌ 混淆 MySQL 两阶段提交和分布式 2PC
- ❌ binlog 和 redo log 可以不一致——两阶段就是保证一致
💡 记忆锚点
两阶段提交像签合同:先在草稿上签字盖章(redo prepare + 刷盘),再把正式合同寄出去(binlog 刷盘),最后在草稿上标"已生效"(redo commit)。宕机恢复时:草稿有签字且正式合同已寄出就补盖"生效"章,正式合同没寄出就撕掉草稿当没发生过。