mysql层事物提交流程

假设参数设置:

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

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刷盘,约等于制定次groupcommit后刷盘,同时会在flush阶段后通知dump线程发送event

 

流程详解解释:

步骤解析第一阶段

备注:在1之前会有一个获取MDL_key::commit 锁的操作,因此ftwrl将会赌赛commit操作,堵塞i状态为waiting for commit lock。

1.binlog 准备,将上一次commit队列中最大的seq number写入到本次事物的last commit中,可参考binlog_prepare函数

2.innodb准备,更改事物的状态为准备并且将事物的状态和XID写入到undo,参考TRX_PREPARE函数

3.XID_EVENT生成并且写道binlog cache中

 

步骤解析第二阶段:

4.形成flush列队。这一步正在不断的有事物加入到这个flush队列。第一个进入flush队列的为本阶段的leader,非leader线程将会堵塞,直到commit阶段后由leader线程唤醒

5.获取LOCK log锁

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

7.这里事物会进行innodb层的redo持久化,并且会帮助其他事物进行redo的持久化。可以参考MySQL_bin_log::process_flush_stage_queue函数

8.生成GTID和SEQ number,并且连接前面的last commit生成gtid_event,然后直接写入到binary log中。--------没有写入binary log cache

对于seqnumber和last commit的取值来说,有三种取值,收到参数binlog_transaction_dependency_tracker来决定.

对于commit_order特点:

8.1 每次事物提交seq number增加1

8.2 last commit 在前面的binlog准备阶段就赋予值给了每个事物

8.3 last commit 是前一个commit队列的最大seq number 

其次seq number和last commit这2个值类型都为logical_clock,其中维护了一个叫做offsets偏移量的值,用来记录每次binary log切换时sequence_number的相对偏移量,因此seq number 和last commit 在每个binary log总是重新计算。

9.将会binlog cache里面的所有event写入到我们的binary log中,包含以下事件(query_event,map_event,dml_event,xid_event)

*******重复7-9  把flush队列中所有的事物做同样的处理

注意:如果sync_binlog !=1 这里将会唤醒DUMP线程进行event的发送

10.这一步还会判断binary log是否需要切换,并且设置一个切换标记。依据就是整个队列每个事物写入的event总量加上现有的binary log大小是否超过max_binlog_size。注意:将所有的event写入binary log然后再进行判断;因此对于大事物来讲event 可定都包含再同一个binary log中。

步骤解析第三阶段:

11.flush 列队加入到sync队列。第一个进入flush列队的leader为本阶段的leader。其他flush列队加入sync队列,且其他flush队列的leader会被lock sync堵塞,直到commit阶段后由leader线程唤醒。

12.释放lock log

13.获取lock sync

14.这里根据参数delay的设置来决定是否等待一段时间,如果delay时间越长那么加入sync队列的时间就会越长,也就可能由更多的flush列队加入进来,那么这个sync队列的事物就越多。不仅会提高sync效率,并且增大了group commit组成员的数量,从而提高MTS的并行效率。

15.这一步就是将sync阶段的队列取出来准备进行并行处理,也就是这个时候sync队列就不能再更改了,这个队列和flush队列不一样,事物的顺序一样但是数量可能不一样。

16.根据sync_binlog的设置决定是否刷盘

-----------------这里sync阶段就结束了,---------如果sync_binlog=1这里将会唤醒DUMP线程进行event的发送

解析第四步

17.sync队列加入到commit队列,第一个进入的sync队列的leader为本阶段的leader。其他sync队列加入commit队列,且其他sync队列的leader会被lock commit堵塞,直到commit阶段后由leader线程的唤醒

18.lock sync

19.lock commit

20.根据参数binlog_order_commits的设置来决定是否按照队列的顺序进行innodb层的提交,如果binlog_order_commits=1 则按照队列顺序提交事物的可见和提交顺序一致。如果binlog_order_commits=0 则下面21到23步将不会进行,事物的顺序一样,数量可能不一样

21.这一步就是将commit阶段的队列取出来进行处理,也就是这个时候commit队列不能再改变了,这个队列和flush队列和sync队列不一样,事物的顺序一样,数量可能不一样

重要:如果rpl_semi_sync_master_wait_point参数设置为after_sync 这里将会进行ACK的确认,可以看到实际innodb层提交操作还没有进行

等待期间状态为‘waiting for semi-sync ACK form slave'

 

22.再innodb层提交之前必须要更改last_commit。commit队列中每个事物都会去更新它,如果大于则更改,小于则不变

23.commit队列中每个事物按照顺寻进行innodb层的提交。可以参考innobase_commit函数

这一步innodb层会做很多动作:readview的更新 undo的状态的更新,innodb锁资源的释放

完成这一步,实际上再innodb层事物就可以看见了。

循环22-23直到commit列队处理完成。

24.释放lock commit

如果rpl_semi_sync_master_wait_point参数设置为after_commit ,这里将会进行ACK的确认,

可以看到实际innodb层提交操作已经完成了,等待期间状态为‘waiting for semi-sync ACK form slave'

到这里commit阶段结束了。

 

25.这里leader线程唤醒所有组内的成员,各自进行各自的操作

26.每个事物成员进行binlog cache的重置,清空cache释放临时文件

27.如果binlog_order_commit设置为0,commit队列中的每个事物就各自进行innodb层面的提交

28.根据10设置的切换标记,决定是否进行binary log的切换

29.如果切换了binary log,则还需要根据expire_logs_days的设置判断是否进行binlog的清理

 

posted @ 2020-10-22 13:54  和尚也爱看AV  阅读(229)  评论(0)    收藏  举报