mysql主从同步(5)-同步延迟状态考量(seconds_behind_master和pt-heartbea)

 

通常状况下,咱们是经过"show slave status \G;"提供的Seconds_Behind_Master值来衡量mysql主从同步的延迟状况。具体说明见:mysql主从同步(4)-Slave延迟状态监控,这种方法在大多数状况下确实是可行的。可是经验告诉我,仅仅依靠Seconds_Behind_Master的值来监测主从同步数据是否延迟是绝对不可靠的!!!html

曾经遇到过的一个坑:
Mysql主从环境部署后,刚开始主从数据同步是没问题的,也是经过监控Seconds_Behind_Master的值来判断同步是否延迟。可是运行一段时间后,忽然有一天发现,主库上写入新数据后,从库并无按时同步过来!!因而,马上在从库上执行"show slave status \G;"发现Seconds_Behind_Master为0 ,而且Slave_IO_Running和Slave_SQL_Running线程状态都是YES也就是说从库到主库的链接还在,没有断开!可是主库上的变动数据就是长时间没法同步到从库上。若是没有人为干预,直到一个小时之后,从库才会自动从新链接主库,进而才继续同步主库的变动
发生这种状况时,经过通常的正常监控方式是不会发现从库有数据延迟。因而可知,仅仅经过Seconds_Behind_Master=0来判断同步是否延迟显然是不够滴.........mysql

发现这个问题之后,咱们人工干预的操做只是须要在从库上执行下面两步从新复制就能解决此问题:
mysql> stop slave;
mysql> start slave; sql

从新执行复制后,要尽快修改slave_net_timeout这个参数数据库

之因此要等1小时才能从新同步,是由于slave_net_timeout这个参数默认的就是3600s,它是设置在多少秒没收到主库传来的Binary Logs events以后,从库认为网络超时,Slave IO线程会从新链接主库。网络

mysql> show variables like 'slave_net_timeout';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| slave_net_timeout | 3600  |
+-------------------+-------+
1 row in set (0.00 sec)

若是在部署mysql主从同步的时候,没有在从库这边设置好slave_net_timeout这个参数,遇到上面的状况,它就会按照默认的3600s(一小时)采起自动从新链接主库,而后才能继续同步主库的变动。这个参数不能设置太大,太大会形成数据库延迟或者主备库直接的连接异常不能及时发现可是设置过小又会形成主库没有数据更新时频繁重连。
至于slave_net_timeout这个参数究竟设置多少,要根据本身的mysql主库数据更新的频繁程度:主库数据更新频繁的,就将这个参数值设小点,更新不频繁就设大点。
通常这个参数设置5s、10s、15s、20s、30s等等。运维

设置方法:
直接登录从库的mysql在线修改:工具

mysql> set global slave_net_timeout = 5;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show variables like 'slave_net_timeout';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| slave_net_timeout | 5     |
+-------------------+-------+
1 row in set (0.01 sec)

或者在从库的myc.nf里添加:
[root@slave-server ~]# cat /usr/local/mysql/my.cnf
....
[mysqld]
.....
slave_net_timeout = 5
[root@slave-server ~]# /etc/init.d/mysql restartspa

所以,将这个参数设置恰当后,遇到上面问题的时候,从库就会按照设定的时间去主动从新链接主库同步数据,就不须要人工干预。线程

固然,上述场景是很是特殊的,通常出现的几率比较小,可是做为运维人员,咱们很是有必要搞清楚该怎么应对这种状况。这就须要咱们要更加深刻的吃透MySQL replication重试机制。rest

接下来基于mysql主从复制原理来分析这一现象
MySQL的Replication是区别其余数据库很关键的地方,也是可扩展性和高可用的基础。它自己已经很是智能化,只须要咱们调用Change Master指定Binlog 文件名和偏移位置就能够搭建从主库到备库的复制关系。
MySQL复制线程会自动将目前复制位置记录下来,在主备复制中断的时候自动连上主库,并从上次中断的位置从新开始复制。这些操做都是全自动化的,不须要人为的干预。这给了咱们运维人员带来了不少便利,同时也隐藏了不少细节。要真正的理解前面问题的真相以及怎么解决这个问题,咱们仍是须要真正的理解MySQL复制的原理。

1)Mysql主从复制的动做是“推”仍是“拉”
MySQL的复制是“推”的,而不是“拉”的。
“拉”是指MySQL的备库不断的循环询问主库是否有数据更新,这种方式资源消耗多,而且效率低。
“推”是指MySQL的主库在本身有数据更新的时候推送这个变动给备库,这种方式只有在数据有变动的时候才会发生交互,资源消耗少。
显而易见,“推”的方式更加符合程序运行的节能原则。

那么MySQL具体是怎么“推”的列呢?
实际上备库在向主库申请数据变动记录的时候,须要指定从主库Binlog的哪一个文件(MASTER_LOG_FILE)的具体多少个字节偏移位置(MASTER_LOG_POS)。对应的,主库会启动一个Binlog dump的线程,将变动的记录从这个位置开始一条一条的发给备库。备库一直监听主库过来的变动,接收到一条,才会在本地应用这个数据变动。

2)缘由解析
从上面的分析,咱们能够大体猜到为何 show slave status 显示一切正常,可是实际上主库的变动都没法同步到备库上来:
出现问题的时候,Binlog dump程序被kill掉了。而备库做为监听的一方,它一直没有收到任何变动,它会认为主库上长时间没有任何变动,致使没有变动数据推送过来。
备库是没法判断主库上对应的Binlog dump线程究竟是意外终止了,仍是长时间没有任何数据变动的。因此,对这两种状况来讲,备库都显示为正常。

因此该问题的关键在于:
主库Binlog dump线程kill的消息因为网络堵塞或者其余缘由没法发送到备库,而备库却认为主库上的数据给有变动,由于双方数据产生了差别。
而备库只能在默认的3600s后主动地从新去链接主库,届时它才会发现主库的数据有变更了,才会自动同步过来,这是须要等待很长时间。

3)问题避免
基于上面的分析,能够知道MySQL在这种状况下确实没法避免,那么有哪些办法能够避开:
   1--被动处理:修改延迟的监控方法,发现问题及时处理。
   2--主动预防:正确设置--master-retry-count ,--master-connect-retry ,--slave-net-timeout 复制重试参数。

   1--被动处理
   MySQL的延迟监控大部分直接采集show slave status中的Seconds_Behind_Master 。
   那么像上面说的这种状况下, Seconds_Behind_Master就没法用来真实的衡量主备之间的复制延迟了。
   推荐使用Percona提供的监控方案(参考:mysql主从同步(3)-percona-toolkit工具(数据一致性监测、延迟监控)使用梳理

   2--主动预防
   除了手动在从库上stop slave和start slave从新执行复制后,还须要指定三个参数,用于复制线程重连主库,分别是
   master-retry-count:链接重试的次数。
   master-connect-retry:链接失败后等待的秒数
   slave-net-timeout:上面已介绍
   其中 master-connect-retry 和 master-retry-count 须要在 Change Master 搭建主备复制时指定,而 slave-net-timeout 是一个全局变量,能够在 MySQL 运行时在线设置。
   不过要注意的是:master-connect-retry和master-retry-count参数在Mysql5.6版本里就被去除了,因此Mysql5.6版本及更高版本就只设置slave-net-timeout参数即可。

  具体的重试策略为:
  备库过了slave-net-timeout秒尚未收到主库来的数据,它就会开始第一次重试。而后每过 master-connect-retry 秒,备库会再次尝试重连主库。直到重试了 master-retry-count 次,它才会放弃重试。若是重   试的过程当中,连上了主库,那么它认为当前主库是好的,又会开始 slave-net-timeout 秒的等待。

  slave-net-timeout 的默认值是3600 秒, master-connect-retry默认为60秒, master-retry-count默认为86400次。  也就是说,若是主库一个小时都没有任何数据变动发送过来,备库才会尝试重连主库。  这就是为何我遇到场景下,一个小时后,备库才会重连主库,继续同步数据变动的缘由。  这样的话,若是你的主库上变动比较频繁,能够考虑将slave-net-timeout设置的小一点,避免主库 Binlog dump 线程 终止了,没法将最新的更新推送过来。  固然 slave-net-timeout 设置的太小也有问题,这样会致使若是主库的变动确实比较少的时候,备库频繁的从新链接主库,形成资源浪费。

相关文章
相关标签/搜索