景:

由于业务要求,需要在国外和国内两台服务器之间做数据库主从,由于业务也不是很大,就简单部署了个主从就用了,开始也没什么问题,最近一段时间,可能是跨国网络不稳定,在主库上更新的内容,从库上迟迟没有更新


问题分析:

上数据库查发现IO thread的running状态是YES,SQL thread的running状态是正常的,但是从库Pos差了主库很多,而且Seconds_Behind_Master值也一直在增加,从库也没有报任何故障,主库也正常,看来是网络不稳定,从库没有从主库上dump?


在MySQL的复制协议里,由Slave发送一个COM_BINLOG_DUMP命令后,就完全由Master来推送数据,Master、Slave之间不再需要交互。如果 Master 没有更新,也就不会有数据流,Slave 就不会收到任何数据包。但是如果由于某种原因造成 Master 无法把数据发送到 Slave ,比如发生过网络故障或其他原因导致 Master 上的 TCP 连接丢失,由于 TCP 协议的特性,Slave 没有机会得到通知,所以也没法知道收不到数据是因为 Master 本来就没有更新呢还是由于出了故障


为什么延迟后从库没有去重新链接主库吗?


其实从库和主库之间有重试机制,整个重试过程是当从库发现从主库上无法获得更多的数据了,就会等待slave_net_timeout时间,然后将IO thread置为no状态,接着开始尝试重建建立连接,每次建立失败之后等待master_connect_retry时间,一直重试master_retry_count次


整个过程就是这三个参数控制,三个参数分别解释如下:

  • slave_net_timeout意味着在没有得到更多数据之后slave等待的时间,默认值3600s 

  • master_connect_retry意味着每次和主库建立链接重试的等待时间,默认值为60s 

  • master_retry_count意味着从库同主库建立链接的重试次数,默认86400次

slave_net_timeout可以通过show variables like 'slave_net_timeout'查看,另外两个参数可以通过show slave status查看

MySQL主从网络延迟解决_java

所以,为了解决上面的问题,可以缩短slave-net-timeout的时间,更早的发现问题,通过set global来修改


而另外两个参数可以在建立主从关系的时候通过change master的时候添加修改


除了上面三个配置外,还有一个关键的配置,就是下MySQL5.5之后引入的master_heartbeat_period,即复制心跳,它能在复制停止工作和出现网络中断的时候帮助快速发现问题


复制心跳的周期取值范围为0~4294967秒,精确度可以达到毫秒,最小非0值为0.001。心跳信息由master在主机binlog日志文件在设定的间隔时间内没有收到新的事件时发出,以便让slave知道master是正常的,它的默认值是slave_net_timeout的值除以2,设置为0表示完全的禁用心跳,下面的图看一下默认配置   


MySQL主从网络延迟解决_java_02


虽然配置名称是master_heartbeat_period,但是查询的时候是Slave_hertbeat_period,这个就是复制心跳的间隔时间


slave_last_heartbeat是代表上次心跳检测的时间

slave_received_heartbeats是代表总共收到的检测次数


可以通过change master to master_heartbeat_period = 10;来修改该配置的值,3个小时时间太长了,所以这里修改到10s,这样Master 在没有数据的时候,每 10 秒发送一个心跳包。这样 Slave 就能知道 Master 是不是还正常。slave_net_timeout 是设置在多久没收到数据后认为网络超时,之后 Slave 的 IO 线程会重新连接 Master 。结合这两个设置就可以避免由于网络问题导致的复制延误

MySQL主从网络延迟解决_java_03


修改完成后,通过脚本记录主库的Master_Log_Pos和从库的Read_Master_Log_Pos,并记录执行时间来对比查看延迟时间

MySQL主从网络延迟解决_java_04

修改之后基本没有延迟的情况


另外通过脚本的形式,监控主从同步状态并通过邮件告警

MySQL主从网络延迟解决_java_05

本来想找免费的短信的,没找着,就先邮件凑合着,有更好的方法欢迎留言推荐,感激不尽!