MySQL层事务提交的流程

  介绍

本篇内容主要讲解“MySQL层事务提交的流程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL层事务提交的流程”吧!

本节将来解释一下MySQL层详细的提交流程,但是由于能力有限,这里不可能包含全部的步骤,只是包含了一些重要的并且我学习过的步骤。我们首先需要来假设参数设置,因为某些参数的设置会直接影响到提交流程,我们也会逐一解释这些参数的含义。本节介绍的大部分内容都集中在函数MYSQL_BIN_LOG::prepare和MYSQL_BIN_LOG::ordered_commit之中。

一、参数设置

本部分假定参数设置为:

  • binlog_group_commit_sync_delay:0

  • binlog_group_commit_sync_no_delay_count:0

  • binlog_order_commits:ON

  • sync_binlog:1

  • binlog_transaction_dependency_tracking:COMMIT_ORDER

关于参数binlog_transaction_dependency_tracking需要重点说明一下。我们知道Innodb的行锁是在语句运行期间就已经获取,因此如果多个事务同时进入了提交流程(prepare阶段),在Innodb层提交释放Innodb行锁资源之前各个事务之间肯定是没有行冲突的,因此可以在从库端并行执行。在基于COMMIT_ORDER 的并行复制中,last commit和seq number正是基于这种思想生成的,如果last commit相同则视为可以在从库并行回放,在19节我们将解释从库判定并行回放的规则。而在基于WRITESET的并行复制中,last commit将会在WRITESET的影响下继续降低,来使从库获得更好的并行回放效果,但是它也是COMMIT_ORDER为基础的,这个下一节将讨论。我们这节只讨论基于COMMIT_ORDER 的并行复制中last commit和seq number的生成方式。

而sync_binlog参数则有两个功能:

  • sync_binlog=0:binary log不sync刷盘,依赖于OS刷盘机制。同时会在flush阶段后通知DUMP线程发送Event。

  • sync_binlog=1:binary log每次sync队列形成后都进行sync刷盘,约等于每次group commit进行刷盘。同时会在sync阶段后通知DUMP线程发送Event。注意sync_binlog非1的设置可能导致从库比主库多事务。

  • sync_binlog>1:binary log将在指定次sync队列形成后进行sync刷盘,约等于指定次group commit后刷盘。同时会在flush阶段后通知DUMP线程发送Event。

二、总体流程图

这里我们先展示整个流程,如下(图15-1,高清原图包含在文末原图中):

 MySQL层事务提交的流程

<人力资源/>

三,步骤解析第一阶段(图中蓝色部分)

<强>注意:在第1步之前会有一个获取MDL_key::提交锁的操作,因此FTWRL将会堵塞”提交“操作,堵塞状态为“等待提交锁”,这个可以参考FTWRL调用的函数make_global_read_lock_block_commit。

(1。),binlog准备。将上一次提交队列中最大的seq数量写入到本次事务的last_commit中。可参考binlog_prepare函数。

(2。),Innodb准备。更改事务的状态为准备并且将事务的状态和XID写入到撤销中。可参考trx_prepare函数。

(3。),XID_EVENT生成并且写到binlog缓存中。在第十节中我们说过实际上XID来自于query_id,早就生成了,这里只是生成事件而已。可参考MYSQL_BIN_LOG::提交函数。

<人力资源/>

,四步骤解析第二阶段(图中粉色部分)

(4。),形成冲队列。这一步正在不断的有事务加入到这个冲洗队列。第一个进入平队列的为本阶段的领导者,领导者非线程将会堵塞,直到提交阶段后由领袖线程的唤醒。

(5。),获取日志锁锁。

(6。),这一步就是将冲阶段的队列取出来准备进行处理,也就是这个时候本平队列就不能在更改了。可参考stage_manager.fetch_queue_for函数。

(7。),这里事务会进行Innodb层的重做持久化,并且会帮助其他事务进行重做的持久化。可以参考MYSQL_BIN_LOG:: process_flush_stage_queue函数。下面是注释和一小段代码:

<>之前,/*   ,,,flush 我方表示歉意prepared  records  of  transactions 用,log  of 存储   ,,,engine  (for 例如,,InnoDB  redo 日志),拷贝a  group  right 之前   ,,,flushing  them 用binary 日志。   ,*/ha_flush_logs才能(零,,真的);//做innodb 重做持久化

(8。)生成GTID和seq号码,并且连同前面去年提交的生成GTID_EVENT,然后直接写入到二进制日志中。我们注意到这里直接写入到了二进制日志而没有写入到binlog缓存,因此GTID_EVENT是事务的第一个事件。参考函数binlog_cache_data::冲洗中下面一段:

MySQL层事务提交的流程