MySQL两阶段提交、崩溃恢复与组提交

一、两阶段提交

1.1 XA概念

  XA(分布式事务)规范主要定义了事务管理器 (TM)和资源管理器(RM)之间的接口。XA为了实现分布式事务,将事务的提交分成了两个阶段:也就是2PC,XA协议就是通过将事务的提交分为两个阶段来实现分布式事务。
两阶段:
prepare 阶段
  TM向RM发出prepare指令,RM进行操作,然后返回成功与否的信息给TM。
commit 阶段
  事务提交或者回滚阶段,如果TM收到所有RM的成功消息,则TM向RM发出提交指令;不然则发出回滚指令。

1.2 MySQL的XA

  MySQL XA分为两类,内部XA与外部XA;

  • 外部XA用于跨多个MySQL实例的分布式事务,需要应用层介入作为协调者(崩溃时的悬挂事务,全局提交还是回滚,需要由应用层决定,对应用层的实现要求较高);
  • 内部XA用于同一实例下跨多个引擎的事务,由binlog作为协调者;最常见的内部XA事务存在于binlog与InnoDB redo之间,从而保证了主从环境的数据一致性。

内部XA将事务的提交分为两个阶段,解决了 binlog 和 redo log的一致性问题。
  MySQL为了兼容其它非事务引擎的复制,在server层面引入了 binlog, 它可以记录MySQL所有引擎中的修改操作,因而可以用于主从复制功能。但是引入了binlog,MySQL server层的binlog与innodb 引擎层的redo的一致性问题。

1.3 二阶段提交

prepare阶段

  • InnoDB prepare,持有prepare_commit_mutex,并且write/sync redo log; 将回滚段设置为Prepared状态,binlog不作任何操作;

commit阶段

  • write/sync Binlog;
  • InnoDB commit (写入COMMIT标记后释放prepare_commit_mutex);

二阶段提交中以binlog 的写入与否作为事务提交成功与否的标志,innodb commit标志并不是事务成功与否的标志。

innodb_support_xa:默认为true,表示启用XA,虽然它会导致一次额外的磁盘flush(prepare阶段flush redo log). 但是必须启用,而不能关闭它。因为关闭会导致binlog写入的顺序和实际的事务提交顺序不一致,会导致崩溃恢复和slave复制时发生数据错误。如果启用了log-bin参数,并且不止一个线程对数据库进行修改,那么就必须启用innodb_support_xa参数。

二、崩溃恢复

2.1 崩溃恢复过程

  • 当实例从崩溃中恢复时,需要将活跃的事务从undo中提取出来,先做redo,undo是受redo 保护的,因此可以从redo中恢复(临时表undo除外,临时表undo是不记录redo的)。

  • 崩溃恢复时,扫描最后一个Binlog文件,提取其中的xid;

  • InnoDB维持了状态为Prepare的事务链表,将这些事务的xid和Binlog中记录的xid做比较,如果在Binlog中存在,则提交,否则回滚事务。

    扫描二维码关注公众号,回复: 11576992 查看本文章
binlog每次rotate到一个新的binlog文件之前,总是要保证前一个binlog文件中对应的事务都提交并且sync redo到磁盘了,也就是说,前一个binlog文件中的事务在崩溃恢复时肯定是出于提交状态的.

  通过这种方式,可以让InnoDB和Binlog中的事务状态保持一致。如果在sync binlog后崩溃,恢复时则会重新对commit标志进行写入;在sync binlog前崩溃,则会回滚;

崩溃恢复是以binlog中的xid和redo log中的xid进行比较,xid在binlog里存在则提交,不存在则回滚。

三、binlog 组提交

3.1 为什么需要组提交

  当sync_binlog=1时,很明显上述的commit阶段中的 write/sync binlog会成为瓶颈,而且还是持有全局锁(prepare_commit_mutex: prepare 和 commit共用一把锁),这会导致性能急剧下降。解决办法就是在MySQL5.6中引进的binlog组提交。

3.2 组提交原理

Binlog Group Commit的过程拆分成了三个阶段

  • flush stage 将各个线程的binlog从cache写到文件中;
  • sync stage 对binlog做fsync操作(如果需要的话;最重要的就是这一步,对多个线程的binlog合并写入磁盘);
  • commit stage 为各个线程做引擎层的事务commit(这里不用写redo log,在prepare阶段已写)。
      每个stage同时只有一个线程在操作。(分成三个阶段,每个阶段的任务分配给一个专门的线程,并发优化)。这种实现的优势在于三个阶段可以并发执行,从而提升效率。

猜你喜欢

转载自blog.csdn.net/qq_42979842/article/details/107840971