MySQL 事务的二阶段提交是什么?
两阶段提交Two-Phase Commit, 2PC是分布式事务或跨存储引擎事务中为了保证数据一致性Atomicity而采用的一种协议。在 MySQL 中2PC 最典型的应用场景是InnoDB 存储引擎与 Redo Log重做日志和 Binlog二进制日志之间的协作。1. 为什么需要两阶段提交在 MySQL 中为了兼顾性能和可靠性采用了双日志机制Redo Log (InnoDB 特有)作用保证事务的持久性Crash-safe。即使数据库崩溃重启后也能通过 Redo Log 恢复未刷盘的数据。特点循环写入写入性能极高顺序写但只记录“在某个数据页上做了什么修改”不记录 SQL 逻辑。Binlog (Server 层通用)作用用于主从复制和数据恢复逻辑备份。特点追加写入记录 SQL 逻辑或行变更是逻辑日志。问题所在如果这两个日志的写入不是原子的就会发生数据不一致场景 ARedo Log 写成功了但 Binlog 写失败了或崩溃了。结果重启后InnoDB 通过 Redo Log 恢复了数据但 Binlog 里没有这条记录。主从复制时从库没有这条数据导致主从数据不一致。场景 BBinlog 写成功了但 Redo Log 写失败了或崩溃了。结果重启后InnoDB 发现没有 Redo Log认为事务未提交数据回滚。但 Binlog 里却有这条记录。如果基于 Binlog 恢复会错误地插入这条数据导致数据错误。解决方案必须保证Redo Log和Binlog要么同时成功要么同时失败。这就是两阶段提交2PC存在的意义。2. 两阶段提交的具体流程MySQL 的 2PC 将事务提交过程分为两个阶段Prepare准备阶段和Commit提交阶段。第一阶段Prepare准备阶段事务执行完毕所有数据修改已写入内存Buffer Pool。InnoDB 引擎将 Redo Log 写入磁盘状态标记为prepare预提交。此时Redo Log 中记录了事务 ID但事务尚未正式提交。关键点此时如果数据库崩溃重启后 InnoDB 会检查 Redo Log。如果是prepare状态InnoDB 会去检查 Binlog 是否完整。Server 层收到 InnoDB 的prepare成功信号后开始写入Binlog。Binlog 写入是追加写一旦写入即持久化。第二阶段Commit提交阶段如果Binlog 写入成功Server 层通知 InnoDB 引擎执行Commit。InnoDB 将 Redo Log 的状态从prepare更新为commit。事务正式结束数据对外可见。如果Binlog 写入失败Server 层通知 InnoDB 引擎执行Rollback。InnoDB 回滚事务Redo Log 标记为无效。事务结束数据不对外可见。3. 崩溃恢复机制Crash Recovery2PC 的核心价值在于崩溃恢复。当 MySQL 重启时InnoDB 会扫描 Redo Log根据日志状态决定如何处理Redo Log 状态Binlog 状态恢复动作原因Commit任意提交事务已完全提交无需检查 Binlog。Prepare完整存在提交说明 Binlog 写成功了只是 Redo Log 还没刷成 commit。为了保持主从一致必须提交。Prepare不存在/损坏回滚说明 Binlog 没写成功或崩溃在 Binlog 写入前。为了数据一致性必须回滚否则主从会不一致。关键点InnoDB 在恢复prepare状态的事务时会去检查对应的 Binlog 文件。如果 Binlog 里能找到该事务的记录就提交找不到就回滚。这保证了Redo Log和Binlog的严格一致性。4. 2PC 的优缺点优点数据强一致性完美解决了 Redo Log 和 Binlog 不一致的问题保证了主从复制的数据准确性。Crash-safe即使数据库在事务提交的任何中间环节崩溃重启后也能自动恢复到一致状态不会丢失数据也不会产生脏数据。缺点性能开销事务提交需要写两次磁盘Redo Log 写一次Binlog 写一次且中间有状态切换。相比单阶段提交增加了 I/O 次数和锁持有时间。阻塞风险在 Prepare 阶段事务持有的锁不会释放。如果 Binlog 写入慢或网络延迟会导致事务长时间持有锁可能引发死锁或性能下降。单点故障在分布式数据库如 MySQL Cluster 或基于 2PC 的分布式事务中如果协调者Coordinator在第二阶段崩溃参与者Participant可能会一直阻塞在 Prepare 状态直到超时。5. 如何优化或关闭 2PC在 MySQL 中有一个参数sync_binlog和innodb_flush_log_at_trx_commit会影响 2PC 的性能和安全性但2PC 协议本身是默认开启且无法关闭的为了保证数据一致性。但是可以通过调整参数来平衡性能sync_binlog 1(默认最安全)每次事务提交都强制刷盘 Binlog。配合 2PC性能最低但最安全。sync_binlog N每 N 次事务提交刷盘一次 Binlog。性能提升但崩溃可能丢失 N 次 Binlog配合 2PC 可能导致主从短暂不一致但重启后 InnoDB 会回滚未刷 Binlog 的事务所以数据最终一致只是主从延迟。innodb_flush_log_at_trx_commit 1(默认)每次事务提交都刷 Redo Log。注意在 MySQL 5.7 和 8.0 中引入了Group Commit组提交机制极大地优化了 2PC 的性能。原理多个并发事务在 Prepare 阶段完成后不会立即去写 Binlog而是等待一小段时间将多个事务的 Binlog 合并成一次磁盘 I/O 写入。效果在高并发场景下显著减少了磁盘 I/O 次数提升了吞吐量同时保持了 2PC 的一致性。总结MySQL 的两阶段提交是连接InnoDB 存储引擎和Server 层 Binlog的桥梁。核心目的确保 Redo Log 和 Binlog 的原子性防止主从数据不一致。流程先写 Redo Log (Prepare) - 再写 Binlog - 最后写 Redo Log (Commit)。恢复重启时根据 Redo Log 的prepare状态和 Binlog 的存在与否决定提交还是回滚。代价牺牲了一定的写入性能换取了数据的绝对安全。对于绝大多数生产环境强烈建议保持 2PC 开启不要为了性能关闭它否则主从复制的数据一致性将无法保证。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2433455.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!