- MTS和单线程的不同
上面的第3点只适用于MTS,单SQL线程不同,会去将last_master_timestamp设置为0,代码如下:
if (!rli->is_parallel_exec()) rli->last_master_timestamp= 0;
言外之意单SQL线程计算延迟的公式为:
- 主库当前的时间 - 1970年1月1日0点 - 主从时间的差值
因此看起来计算出来的延迟会更大。
- 最后需要注意的是实际上这种情况的延迟并没有问题,完全是一种偶尔出现的计算上的问题,是一种假象,如果主库的压力越大出现这种情况的可能性就会越大,因为IO线程和SQL线程在处理Read_Master_Log_Pos和Exec_Master_Log_Pos的出现时间差的可能性就会越大。
四、MTS下的延迟debug
其实知道了原理就很容易debug了,因为我们可以将断点放到主库的show_slave_status_send_data函数上,那么就能看出来了,做的操作如下:
- 从库flush binary logs
- 主库执行一些insert操作
- 主库show slave status
这个时候我们可以跳过(Read_Master_Log_Pos和Exec_Master_Log_Pos存在一定的差值)这个条件,直接通过公式去计算,得到如下结果:
(gdb) p (long)(time(0)- mi->rli->last_master_timestamp)- mi->clock_diff_with_master $6 = 37
延迟就是37秒,因此我们的理论得到了验证。
下面一个debug结果是单SQL线程的,可以看到延迟更是大得离谱。
(gdb) p (long)(time(0)- mi->rli->last_master_timestamp)- mi->clock_diff_with_master $7 = 1592672402
五、其他问题
额外的问题:
- 如果双主双写
S1 | S2 |
T1 | |
T2 | |
T3 |
如果按照上面的理论那么T3的更新的位置可能会被T2事务的位点重置。因为主库的SQL线程通过构建的Rotate_log_event可能会出现Exec_Master_Log_Pos倒退的可能性,这显然是不行的。但是代码中构建Rotate_log_event的逻辑包裹在如下逻辑下面。
if (!cur_log->error) /* EOF */ //当前relay log 已经读取完了 { /* On a hot log, EOF means that there are no more updates to process and we must block until I/O thread adds some and signals us to continue */ if (hot_log) //如果是 当前relay log
我们可以看到只有在当前 relay log读取完成后才会进行Rotate_log_event的构建。因此不存在此问题。
- 问题如上虽然不构建Rotate_log_event,但是如果rli->ign_master_log_name_end[0]如果一直保留那么当relay log应用完成后,依旧会去构建Rotate_log_event导致Exec_Master_Log_Pos倒退,实际上这个问题也不会出现,因为在每次IO线程Event写入到relay log后会重置,如下:
rli->ign_master_log_name_end[0]= 0; // last event is not ignored
Enjoy MySQL :)
全文完。