redo log 是 InnoDB 的恢复事实,binlog 是 Server 层和复制链路的提交事实。MySQL 分层之后,一个事务提交就不再只是“写成功”这么简单,而是要让这两套事实在崩溃恢复后仍然对得上。

两阶段提交解决的正是这个边界问题:先让 InnoDB 进入 prepare 状态,再写 binlog,最后提交 InnoDB。它不负责让提交更快,而是让本地事务、复制和恢复面对同一个结果。

先把机制边界说清楚

两阶段提交解决的是 InnoDB redo 和 Server 层 binlog 的一致性问题。提交被拆成 prepare 和 commit 两个阶段:先让 InnoDB 进入可提交状态,再写 binlog,最后让 InnoDB 正式提交。崩溃恢复时通过 binlog 和 redo prepare 状态互相校验。

整体路径

两阶段提交:redo log 和 binlog 怎么不打架

上面这张图先看入口和边界:宏观上,一个事务提交时先写 redo prepare,表示 InnoDB 已经准备好提交;然后 Server 层写 binlog 并刷盘;最后 InnoDB 写 redo commit。崩溃发生在不同点位时,恢复逻辑会根据 binlog 中是否存在对应事务来决定提交还是回滚。

两阶段提交的三步内部结构

第二张图再看结构关系。

底层流程

崩溃恢复时怎么判断事务提交状态

底层拆解先看数据结构。「两阶段提交」至少涉及下面几类结构:

  • redo prepare 记录:表示事务已经完成存储引擎层准备。
  • binlog event:Server 层对外可复制、可恢复的提交事实。
  • XID:关联 redo 和 binlog 中同一事务的标识。
  • redo commit 记录:表示事务在 InnoDB 中最终提交。
  • 崩溃恢复流程:重启时解决 prepare 事务的去留。

再看完整执行流程:

  1. 事务执行完成,InnoDB 写 redo prepare。
  2. Server 层写入 binlog event,并按策略刷盘。
  3. InnoDB 写 redo commit,事务对外提交成功。
  4. 如果崩溃发生在 prepare 后,恢复时检查 binlog 是否有对应 XID。
  5. binlog 存在则提交,binlog 不存在则回滚。

取舍与边界

版本差异上,MySQL 5.7 和 8.0 都依赖这条两阶段提交链路保证 redo 与 binlog 一致。8.0 在事务型数据字典、原子 DDL 和复制元数据上增强很多,但普通事务提交的核心协调关系仍然成立。

两阶段提交提高了一致性,但也把提交路径拉长了。redo 和 binlog 都可能涉及刷盘,组提交能缓解但不能消除 fsync 成本。高并发写入下,提交阶段的磁盘抖动会直接反映到业务延迟。

典型问题:用机制化例子排查

提交阶段变慢时,不一定是 SQL 执行慢,也可能是 redo 和 binlog 的刷盘成本集中在 commit。排查时要把执行阶段和提交阶段拆开看。

可以落到这些动作:

  • 把事务执行耗时和提交耗时分开观察,commit 慢不一定是锁或索引问题。
  • 根据 RPO 决定 sync_binlog 与 innodb_flush_log_at_trx_commit,不要盲目追求极限吞吐。
  • 控制单事务大小,减少提交阶段一次性日志压力。
  • 复制链路依赖 binlog,一致性参数调整前要评估主从和恢复影响。

收束:让两套事实对齐

两阶段提交不是为了让提交更快,而是让 redo 和 binlog 在崩溃后仍然能对齐。分层架构里,一致性往往不是一个模块完成的,而是靠边界协议维持的。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 MySQL」,欢迎关注公众号 「十三Tech」。后续会继续按机制、图解和实战排查这条线更新。

十三Tech公众号二维码