① 正常shutdown 或者 kill mysqldmysql
结果状态单:程序员
Slave_IO_Running: Connecting Slave_SQL_Running: Yes Last_IO_Errno: 2003
② kill -9 mysqld 或者 reboot 服务器
结果状态:有可能同①,也有多是双Yes(我本身测试的是同①结果,看别人测的有的是双yes)sql
③ 临时断开主库的网络,并 kill 掉主库 MySQL 的 binlog dump 线程服务器
结果状态单:网络
Slave_IO_Running: Yes Slave_SQL_Running: Yes
说明:
网络恢复以后,binlog dump线程已不存在;
主库有新的写入,从库没法同步,可是I/O线程和SQL线程都是YES,SBM也没有延迟并发
主库上记录二进制日志,也就是binlog日志。
备库将主库的二进制日志复制到其本地的中继日志中。首先,备库会启动一个工做线程,称为I/O线程,I/O线程跟主库创建一个普通的客户端链接,而后在主库上启动一个特殊的二进制转存(Binglog Dump)线程,这个转存线程会读取主库上的二进制日志中事件,并发送给从库的I/O线程;若是主库没有更新信息将进入休眠。
备库的SQL线程执行最后一步,该线程从中继日志中读取事件并在备库执行,从而实现备库数据的更新。测试
首先, MySQL 的复制是“推”的,而不是“拉”的。“拉”是指 MySQL 的备库不断的循环询问主库是否有数据更新,这种方式资源消耗多,而且效率低。“推”是指 MySQL 的主库在本身有数据更新的时候推送这个变动给备库,这种方式只有在数据有变动的时候才会发生交互,资源消耗少。若是你是程序员出身,你必定会选择“推”的方式。
那么 MySQL 具体是怎么“推”的列,实际上备库在向主库申请数据变动记录的时候,须要指定从主库Binlog 的哪一个文件 ( MASTER_LOG_FILE ) 的具体多少个字节偏移位置 ( MASTER_LOG_POS ) 。对应的,主库会启动一个 Binlog dump 的线程,将变动的记录从这个位置开始一条一条的发给备库。备库一直监听主库过来的变动,接收到一条,才会在本地应用这个数据变动。线程
从上面的分析,咱们能够大体猜到为何 show slave status 显示一切正常,可是实际上主库的变动都没法同步到备库上来:
出现问题的时候, Binlog dump 程序被咱们 kill 掉了。做为监听的一方,备库一直没有收到任何变动,它会认为主库上长时间没有任何变动,致使没有变动数据推送过来。备库是没法判断主库上对应的Binlog dump 线程究竟是意外终止了,仍是长时间没有任何数据变动的。因此,对这两种状况来讲,备库都显示为正常。
固然, MySQL 会尽可能避免这种状况。好比:
a.在 Binlog dump 被 kill 掉时通知备库 线程 被 kill 掉了。因此咱们重现时须要保证这个通知发送不到备库,也就是说该问题重现的关键在于 Binlog dump 被 kill 的消息因为网络堵塞或者其余缘由没法发送到备库。
b.备库若是长时间没有收到从主库过来的变动,它会每隔一段时间重连主库。日志
基于上面的分析,咱们知道 MySQL 在这种状况下确实没法避免,那么咱们能够有哪些办法能够避开:
(1) 被动处理:修改延迟的监控方法,发现问题及时处理。
(2) 主动预防:正确设置 --master-retry-count , --master-connect-retry , --slave-net-timeout 复制重试参数。code
MySQL 的延迟监控大部分直接采集 show slave status 中的 Seconds_Behind_Master。这种状况下,Seconds_Behind_Master 就没法用来真实的衡量主备之间的复制延迟了。咱们建议经过在主库轮询插入时间信息,并经过复制到备库的时间差来得到主备延迟的方案。 Percona 提供了一种相似的方案 pt-heartbeat 。
发现这个问题之后,咱们只须要 stop slave; start slave; 重启复制就能解决这个问题。
MySQL 能够指定三个参数,用于复制线程重连主库: --master-retry-count , --master-connect-retry , --slave-net-timeout 。其中 master-connect-retry 和 master-retry-count 须要在 Change Master 搭建主备复制时指定,而 slave-net-timeout 是一个全局变量,能够在 MySQL 运行时在线设置。具体的重试策略为:备库过了 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 设置的太小也有问题,这样会致使若是主库的变动确实比较少的时候,备库频繁的从新链接主库,形成资源浪费。