vlambda博客
学习文章列表

MySQL:MTS中显示事务和隐式事务延迟计算的区别和mysqldump死锁

一、问题描述

遇到一个这样的问题

  • 隐式大事务:update db_alart_1.sbtest1 set k=k+'11dcs1' where id between 10000 and 1001000; 延迟从20分钟开始
  • 显示大事务:begin;update db_alart_1.sbtest1 set k=k+'11dcs1' where id between 10000 and 1001000; commit;大部分延迟一会从0开始

二、问题分析

我们以前说过MTS的延迟计算有如下公式

  • 从库服务器时间 - 检查点XID_EVENT header中timestamp的时间 - 主从服务器时间差

这个代码流程获取流程如下:

一、工作线程执行到事务XID_EVENT的时候,会设置如下值:
ptr_group->ts= common_header->when.tv_sec + (time_t) exec_time; 
//Seconds_behind_master related  //checkpoint的时候会将这个值再次传递 
//mts_checkpoint_routine() 

二、当进行检查点的时候设置变量ts,调用函数mts_checkpoint_routine
/*
    Update the rli->last_master_timestamp for reporting correct Seconds_behind_master.

    If GAQ is empty, set it to zero.
    Else, update it with the timestamp of the first job of the Slave_job_queue
    which was assigned in the Log_event::get_slave_worker() function.
  */
  ts= rli->gaq->empty()
    ? 0
    : reinterpret_cast<Slave_job_group*>(rli->gaq->head_queue())->ts;
//rli->gaq->head_queue 检查点位置的GROUP的时间

三、更改last_master_timestamp值为ts变量,函数Relay_log_info::reset_notified_checkpoint

last_master_timestamp= new_ts;//设置last_master_timestamp为ts

也就是如下:左边<---右边 GAP队列表示

x代表是已经提交的位置,o代表正在执行,检查点已经做到了LWM位置,GAP队列出队了,那么计算就是第一个o位置xid event的时间。

显然我们知道的是

  • 显示事务,xid event记录的时间为commit命令发起的时间
  • 隐式事务,xid event记录的时间为语句发起的时间

那么在计算延迟的时候,显示事务从0开始计数,隐式事务从主库执行时间开始计数。

因此我们得出结论:如果长期没有新的事务那么GAP队列会出队完成,且清空。当新的事务到来 第一个GTID EVENT会分配GROUP元素,并且放入GAP队列,

gaq->assigned_group_index= gaq->en_queue(&group);

代表一个事务开始了,那么这个时候,GAP队列就不为空了。当SQL协调线程分配到XID event的时候,会将这个event的 timestap 赋予给GROUP->TS,作为计算延迟的标准。但是这里有一个特殊情况(疑问):事务较大,虽然GTID EVENT分发了但是由于分发实际的数据even的t时间较长,还没来到XID event,那么这个时候GTOUP->TS 到底为何值,要看GROUP 结构的初始化是如何做的了。这个后面在分析一下。

三、测试

测试很简单:

  • 显示大事务从0开始计数。

  • 隐式大事务从主库执行时间开始计数。

仅此记录,不做过多描述。