文档首页/ 云数据库 RDS/ 故障排除/ RDS for MySQL/ 主备复制/ MySQL主备复制延迟场景及解决方案
更新时间:2024-10-24 GMT+08:00

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日志的应用速度,产生复制延迟。

排查方法:

通过show create table xxx,分析执行慢的update和delete语句对应的表,分析是否有主键。

解决方法:

给无主键表增加主键,或者酌情增加唯一二级索引。

场景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锁视图

解决方法:

kill只读节点上阻塞DDL操作的长事务,或者在业务侧提交该长事务。

场景5:只读实例规格小于主实例

只读实例、DRS灾备实例的规格小于主实例时,一旦主实例写负载升高到一定程度,只读实例或DRS灾备实例会因为自身资源不足,无法及时回放Binlog,导致复制时延增加。

解决方法:

只读实例或DRS灾备实例扩大规格,与主实例规格匹配。

场景6:读业务压力突然增大

只读库除了要同步主库的数据之外还要承担数据读的业务,当读业务压力突增时,可能会影响只读的回放线程,从而导致只读复制时延增加。