
# MySQL主备复制时延场景及解决方案
RDS for MySQL的默认备库、只读实例、自建备库、DRS链路灾备实例均基于MySQL的Binlog复制技术，也称为MySQL主备复制或主从复制技术。主备复制实现又分为异步复制或半同步复制，无论哪种方式，由于业务执行的语句的原因，不可避免地存在主备复制时延。
现象表现为：RDS for MySQL备机或只读存在复制时延过高，甚至产生复制时延大的告警。
#### 场景1：主库执行了大事务
大事务一般指一个事务中包含大量的数据更新操作，例如一个事务包含几万次DML（insert，update，delete）操作、一条SQL语句批量更新了上万行数据等，大事务往往本身的执行时间很长（分钟级）。当主实例执行了大事务后，会产生大量的Binlog日志，备机或只读节点拉取这些Binlog耗时比一般事务长，且至少需要花费与主实例相同的时间来回放这些事务的更新，从而导致备机或只读节点出现复制时延。
排查方法：
- 对于包含大量DML语句的大事务，使用如下命令，找到长时间执行的事务。
  ```
  select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G;
  ```
  
- 对于一条SQL语句执行大量数据的大事务，执行**show full processlist**，查找是否存在长时间执行的delete或update语句。
- 分析全量日志或慢日志，检查是否有大事务。
解决方法：
- 为了保证主从数据的一致性，需要等待大事务执行完成，主备复制时延才能恢复。
- 业务侧避免此类大事务，可以将大事务拆分为小事务，分批执行。例如，通过where条件或limit语句限制每次要更新的数据量。
 
#### 场景2：对无主键表更新
RDS for MySQL的Binlog采用row格式，对每一行的数据更新，都会形成row格式Binlog event记录。例如：一个update语句更新100行数据，那么row格式的Binlog中会形成100行update记录，备机或只读回放时会执行100次单行update。
只读节点和备机在回放主库的Binlog event时，会根据表的主键或者唯一二级索引来检索需要更改的行。如果对应表未创建主键，则会产生大量的全表扫描，从而降低了Binlog日志的应用速度，产生复制时延。
排查方法：
通过以下SQL，分析执行慢的update和delete语句对应的表，分析是否有主键。
```
show create table xxx;
```
解决方法：
给无主键表增加主键，或者酌情增加唯一二级索引。
#### 场景3：DDL操作
DDL操作往往执行时间很长，尤其是表数据量很大时。通常情况下，只读节点或备机回放一个DDL操作的时间和主机花费的时间基本一致。因此，当主机执行了大表的DDL操作后，备机和只读节点在回放该DDL期间，复制时间必然是一直增大的。
解决方法：
该场景为正常现象，等DDL执行完成后，主备复制时延才能恢复。建议在业务低峰期执行DDL操作。
#### 场景4：只读实例等待MDL锁
只读实例上往往有业务流量，如果存在只读长事务正在执行，会阻塞主实例同步过来的相应表的DDL操作，卡在了表MDL锁获取，进而阻塞所有同表的后续Binlog回放，导致复制时延越来越大。
排查方法：
1. 登录只读节点，使用如下命令，观察是否有长时间执行的事务。 **select t.\*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \\G;**
   
2. 查看只读节点的MDL锁视图，观察是否有MDL锁冲突。 **select \* from information_schema.metadata_lock_info;**
   根据MDL锁视图中的线程ID，找到阻塞的session。更多信息，请参见[MDL锁视图](https://support.huaweicloud.com/kerneldesc-rds-mysql/rds_05_0000.html)。
   
解决方法：
kill只读节点上阻塞DDL操作的长事务，或者在业务侧提交该长事务。
#### 场景5：只读实例规格小于主实例
只读实例、DRS灾备实例的规格小于主实例时，一旦主实例写负载升高到一定程度，只读实例或DRS灾备实例会因为自身资源不足，无法及时回放Binlog，导致复制时延增加。
解决方法：
只读实例或DRS灾备实例扩大规格，与主实例规格匹配。
#### 场景6：读业务压力突然增大
只读库除了要同步主库的数据之外还要承担数据读的业务，当读业务压力突增时，可能会影响只读的回放线程，从而导致只读复制时延增加。
