作者:高鹏(网名八怪),《深入理解MySQL主从原理32讲》系列的作者。
系列链接:https://www.jianshu.com/nb/43148932 版本:5.7.29

水平有限有误请谅解

一、问题来源

这是来自我们线上数据库的一个问题。我们是双主单写,这里约定写入的库为主库,没有写入的库为从库。我们的falcon偶尔会进行报警如下(频率很低):

这是非常奇怪的,按理说我是单写的从库没有做任何操作(除了应用Event以外),主库哪来的延迟,并且延迟这么大。在我映像中有朋友问过这个问题,当时没有细细研究。

二、延迟计算的规则

我们还是要看看主从计算延迟的伪代码:

/*The pseudo code to compute Seconds_Behind_Master:if (SQL thread is running)
//如果SQL线程启动了{if (SQL thread processed all the available relay log)
//如果SQL线程已经应用完了所有的IO线程写入的Event{if (IO thread is running)
//如果IO线程启动了print 0;
//设置延迟为0elseprint NULL;
//否则为空值}elsecompute Seconds_Behind_Master;
//如果SQL线程没有应用完所有的IO线程写入的Event,那么需要计算延迟。}elseprint NULL;
//如果连SQL线程也没有启动则设置为空值*/

计算延迟的公式为:

long time_diff= ((long)(time(0)- mi->rli->last_master_timestamp)- mi->clock_diff_with_master);
也就是:
服务器当前时间-Event header中的timestamp - 主从服务器时间差

出现延迟的必要条件:

  • 如果SQL线程没有应用完了所有的IO线程写入的Event,也就是Read_Master_Log_Pos和Exec_Master_Log_Pos存在一定的差值。判定标准为
(mi->get_master_log_pos() == mi->rli->get_group_master_log_pos()) &&(!strcmp(mi->get_master_log_name(), mi->rli->get_group_master_log_name()))

抛开文件名,也就是通过 IO线程读取到主库binary log的位置 和 SQL线程应用到的主库binary log位置进行比较来进行 判断,只要他们出现差值就会进入延迟计算环节。

  • 服务器当前时间-Event header中的timestamp - 主从服务器时间差 这个公式必须出现差值。
    好了接下来带着这两个产生延迟的必要条件来寻求原因。
    关于更多延迟计算的细节参考:
    https://www.jianshu.com/p/033f83314619

三、产生延迟的原因

1.主库:首先主库写到从库的Event,从库会写入到binlog(log_slave_updates 开启),并且从库的DUMP线程会发送给主库,但是主库的IO线程通过SERVER_ID进程判定,将Event进行过滤,不写入主库的relay log,同时会更新主库IO线程读取的位置(Read_Master_Log_Pos),并且更新忽略到的位置(rli->ign_master_log_name_end[0])。代码如下:

  if (!(s_id == ::server_id && !mi->rli->replicate_same_server_id) ||(event_type != binary_log::FORMAT_DESCRIPTION_EVENT &&event_type != binary_log::ROTATE_EVENT &&event_type != binary_log::STOP_EVENT)){mi->set_master_log_pos(mi->get_master_log_pos() + inc_pos);//增加Read_Master_Log_Pos位点,为当前位置memcpy(rli->ign_master_log_name_end, mi->get_master_log_name(), FN_REFLEN); //进行拷贝DBUG_ASSERT(rli->ign_master_log_name_end[0]); //断言存在rli->ign_master_log_pos_end= mi->get_master_log_pos(); //忽略到位点}

2.主库:SQL线程会通过rli->ign_master_log_name_end[0]判定是否有需要跳过的Event,如果有则构建一个Rotate_log_event来跳过这个Event,代码如下:

if (rli->ign_master_log_name_end[0]) //如果跳过的Event存在{/* We generate and return a Rotate, to make our positions advance */DBUG_PRINT("info",("seeing an ignored end segment"));ev= new Rotate_log_event(rli->ign_master_log_name_end,0, rli->ign_master_log_pos_end, exec_relay_log_eventRotate_log_event::DUP_NAME); //构建一个Rotate Event,位置为rli->ign_master_log_name_end[0]= 0;                   //rli->ign_master_log_pos_end,执行这个Event就可以mysql_mutex_unlock(log_lock);exec_relay_log_event     //来更新Exec_Master_Log_Pos位点if (unlikely(!ev)){errmsg= "Slave SQL thread failed to create a Rotate event ""(out of memory?), SHOW SLAVE STATUS may be inaccurate";goto err;}ev->server_id= 0; // don't be ignored by slave SQL threadDBUG_RETURN(ev);}

好了到这里我们知道了Event在主库是如何跳过的,但是注意IO线程和SQL线程在处理Read_Master_Log_Pos和Exec_Master_Log_Pos的时候可能有一定的时间差,那么Read_Master_Log_Pos和Exec_Master_Log_Pos存在一定的差值 的条件就可能会满足,则进入延迟计算环节。

3、主库的SQL线程平时并没有读取到Event,因为所有的Event都被IO线程过滤掉了。因此
Event的 header中的timestamp 不会更新(MTS)。但是如果从库binlog切换的时候,从库至少会传送ROTATE_EVENT给主库,这个时候主库会拿到这个实际的Event,因此Event的 header中的timestamp 更新了。如果刚好遇到主库的IO线程的Read_Master_Log_Pos和Exec_Master_Log_Pos有差值,
那么falcon去查看延迟就会得到一个延迟很大的假象,延迟的计算公式就会变为如下:

  • 主库当前的时候 - 从库上次binlog切换的时间 - 主从时间的差值
    3、MTS和单线程的不同
    上面的第3点只适用于MTS,单SQL线程不同,会去将last_master_timestamp设置为0,代码如下:

     if (!rli->is_parallel_exec())rli->last_master_timestamp= 0;
    

言外之意单SQL线程计算延迟的公式为:

主库当前的时间 - 1970年1月1日0点 - 主从时间的差值
因此看起来计算出来的延迟会更大。

5.最后需要注意的是实际上这种情况的延迟并没有问题,完全是一种偶尔出现的计算上的问题,是一种假象,如果主库的压力越大出现这种情况的可能性就会越大,因为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

五、其他问题

额外的问题:

如果双主双写

如果按照上面的理论那么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 toprocess and we must block until I/O thread adds some andsignals 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

MySQL 双主单写,主库偶尔出现大量延迟的原因相关推荐

  1. mysql双主可以同时写数据_Mysql双主操作

    在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果是双主或者多主,就会增加mysql入 ...

  2. 高可用Mysql架构_Mysql主从复制、Mysql双主热备、Mysql双主双从、Mysql读写分离(Mycat中间件)、Mysql分库分表架构(Mycat中间件)的演变...

    [Mysql主从复制] 解决的问题 数据分布:比如一共150台机器,分别往电信.网通.移动各放50台,这样无论在哪个网络访问都很快.其次按照地域,比如国内国外,北方南方,这样地域性访问解决了. 负载均 ...

  3. MySQL双主架构介绍

    文章目录 一.背景 二.MySQL双主(主主)架构方案 三.MySQL双主架构图 四.MySQL双主架构的优缺点 一.背景 MySQL 主从模式优点 容灾:主数据库宕机后,启动从数据库,用于故障切换 ...

  4. MySQL双主(主主)架构方案

    在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果是双主或者多主,就会增加mysql入 ...

  5. mysql 双主 脑裂_MySQL双主(主主)架构方案

    在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果是双主或者多主,就会增加mysql入 ...

  6. Keepalived+LVS+MySQL双主复制实现读写负载均衡及高可用

    目录 一.Keepalived和LVS简介 1. Keepalived简介 2. LVS简介 二.安装配置 1. 下载安装LVS 2. 下载安装Keepalived 3. Keepalived配置 5 ...

  7. mysql双主不同步问题

    1:碰到的问题 mysql双主数据库数据不同步 错误提示类似于:1032等,不仅1032我跳过后还有其他的各种问题 查询网上后,基本是两种解决方案1:直接跳过这一步错误,但是因为不同步太多了,跳过之后 ...

  8. mysql双主和主从的区别_MySQL群集,主从复制及双主模式

    MySQL主从复制,是一个MySQL的群集,可以很好的解决的单点故障,并且可以进行读写分离来减轻数据库的压力.很多情况下主服务器仅作为写入数据服务器,而构建多个从节点来进行数据读取. 构建主从复制的几 ...

  9. keepalived mysql双主架构图_MySQL双机热备(keepalived+mysql双主)

    科普描述 双机热备是指两台机器都在运行, 但并不是两台机器都同时在提供服务. 当提供服务的一台 出现故障的时候,另外一台会马上自动接管并且提供服务,而且切换的时间非常短. MySQL 双主复制,即互为 ...

最新文章

  1. 安装win下的Anaconda ----针对python3.6.4版本
  2. 微信小程序实践_3点击版面图片获取新闻链接
  3. EasyUI学习总结(二)——easyloader分析与使用
  4. 我国自主播放软件暴风影音挑落微软
  5. 解封装(七):av_read_frame读取帧数据函数分析和产生的空间问题分析,以及AVPacket分析
  6. SQL DATACOMPARE 实现两个数据库的同步处理.
  7. [Hadoop]Sqoop 1.4.2中文文档(二)之数据导出
  8. 使用 Ajax 上传文件
  9. QuartusII-项目工程的时序仿真
  10. 优盘安装红帽linux系统,RedHat Linux系统U盘安装图文教程
  11. 京瓷打印机m5521cdn_京瓷M5521cdn驱动-京瓷ECOSYS M5521cdn打印机驱动下载 v5.1.2106官方版--pc6下载站...
  12. php公网不能访问8080,linux启动tomcat外部浏览器不能访问8080端口解决方案
  13. iphone模拟器中的documentPath
  14. MySQL的sql大于号(小于号)的使用
  15. Google搜索打不开解决办法、Chrome小技巧
  16. shapely库的基础学习
  17. 金融量化数据接口API汇总
  18. cesium城市建筑物光效(cesium篇.23)
  19. linux-nginx部署
  20. Python几种开发工具介绍

热门文章

  1. python机器学习:决策树ID3、C4.5
  2. php 赋予变量现在时间,PHP关于变量和日期处理的面试题
  3. python编辑器是什么_python开发用什么编辑器
  4. 简单计算器 -python
  5. Focal loss及其实现
  6. Win7虚拟机上安装Xcode 4
  7. 简述 JPA 与 Spring Data JPA 与 Hibernate
  8. String与StringBuilder区别总结
  9. PostgreSQL 锁等待跟踪
  10. git push 冲突