MySQL备库滞后与主库

实例

邮件服务在亚马逊RDS上有两个实例(a和b),其中b作为a的备库。我们假设在资源配置相同的情况下出现b远远滞后于a,且b的iops接近于a的两倍,那么为什么会出现这种情况呢?

主从是怎么同步的

客户端连上主库执行语句产生binlog,主库把产生的binlog发给从库,从库拿到binlog执行,执行后和主库达到同步。从库滞后于主库多少时间,可以通过show slave status返回的seconds_behind_master查看。

导致备库延迟的几种可能

  1. 备库所在机器的性能要比主库所在的机器性能差
  2. 备库的压力大,有其他读业务在备库上执行
  3. 大事务
  4. 大表进行DDL
  5. 备库执行主库发送过来的binlog(relay log)太慢

从业务上来看,我们可以排除1,2,4。至于3,由于我们的延时已经超过一天了,那么我们也可以排除。
那么最有可能产生延迟的原因就是5,那么

备库是怎么执行主库发送过来的binlog

我们先来看一下流程图:
MySQL备库滞后与主库
在这个图中我们重点分析一下sql_thread。在从库中,因为我们的MySQL版本是5.6.*,所以我们的执行策略是按库执行。也就是说,RDS中相同数据库的binlog我们只能单线程执行。
由于邮件服务虽然有三个库,但是我们操作频繁的只有一个库,所以从主库同步到从库基本是单线程复制的。

那么现在的问题为什么变成了如下

为什么从库单线程执行主库的binlog会产生滞后和过大的iops

在这里我们就要讲一下binlog和redo log落盘的策略了(binlog是数据库产生的日志,redo log是innodb这种存储引擎产生的日志)
MySQL备库滞后与主库
两种日志的存储基本相同如上图:

  1. 存在内存中
  2. 写到磁盘 (write),但是没有持久化(fsync)
  3. 持久化到磁盘,对应的是 hard disk,也就是图中的绿色部分。
  4. 在黄色区域的多个事务,会由于某些原因,同时持久化到绿色区域

所以备库是单线程执行,只能一次一次的持久化,导致执行时间更长,又由于是一次一次的持久化,导致了一次又一次的iops,所以iops的数量更多

处理方法

下面两个方法二选一:

  1. 将 sync_binlog 设置为大于 1 的值(x),将 innodb_flush_log_at_trx_commit 设置为大于1的值(x),目的是保证不是每个session都要持久化数据,而是要等x个事务才持久化
  2. 取消备库生成binlog