MySQL 两阶段提交
说明
MySQL 开启 Binlog 后,所有的事务都会产生 Binlog Event,这些 Event 也是事务数据的一部分。本篇文章介绍 MySQL 如何保证事务 Binlog Event 和 Innodb 引擎中数据的一致性。
1. MySQL 宕机重启
MySQL 宕机重启后,需要保证如下四点:
所有已提交的事务依然存在。
所有未提交的事务全部回滚。
所有已提交事务的 Binlog 依然存在。
所以未提交的事务没有记录 Binlog。
如果数据库重启后数据还在,但是 Binlog Event 不存在,那么就无法将这部分数据同步到其它节点;
如果数据库重启后数据不存在,但是 Binlog Event 还在,那么就会出现主从数据不一致的问题。
为了保证 Binlog 的宕机安全,MySQL 内部使用了两阶段提交来保证一个事物会涉及多方参与时状态的一致性。
2. 两阶段提交
MySQL 在开启 Binlog 后,MySQL 内部会自动将普通事务当作 XA 事务来处理,在提交事务的过程中,MySQL 会自动为每一个事务分配一个唯一的 XID 会被记录到 Binlog 中 Innodb Redo Log 中。
-- Binlog 中 XID 片段: #210427 11:48:58 server id 553306 end_log_pos 310021 CRC32 0xe92f381e Xid = 80 COMMIT/*!*/;
事务提交时会被分成 Prepare 和 Commit 两个阶段:
Prepare 阶段:告诉 Innodb 引擎做 Prepare,Innodb 更改事务状态,并将 Redo Log 写入磁盘。
Cimmit 阶段:先记录 Binlog 日志,然后告诉 Innodb 引擎提交事务。
在数据库宕机重启后,事务可能有如下四种状态:
innodb 引擎已 Commit 事务:根据两阶段提交可知,事务已被写入 Binlog Event,所以事务是一致的,无需处理。
在 Innodb 中已完成 Prepare 阶段,Binlog 中已有该事务的 Event,但是该事务未提交,需要通知 Innodb 引擎提交这些事务。
在 Innodb 中已完成 Prepare 阶段,Binlog 中没有该事务的 Event,因为没有记录 Binlog,需要通知 Innodb 回滚事务。
Innobd 未完成 Prepare 阶段,根据两阶段提交过程,Binlog 没有记录,需要通知 innodb 回滚事务。