复制延迟

本页面介绍如何排查和修复 Cloud SQL 读取副本的复制延迟问题。

概览

Cloud SQL 读取副本通过全局事务标识符 (GTID) 使用基于 MySQL 行的复制。更改将写入主实例的二进制日志并发送到副本,在副本中接收到它们后应用于数据库。

在几种情况下可能会发生复制延迟,例如:

  • 主实例将更改发送到副本的速度不够快。
  • 副本接收更改的速度不够快。
  • 副本无应用更改的速度不够快。
请使用 network_lag 指标来监控前两种场景:主实例无法足够快地发送更改或副本无法足够快地接收更改。

您可以使用 replica_lag 指标来观察总延迟时间。如果副本应用复制更改的速度不够快,replica_lagnetwork_lag 之间的差异可能表明第三个原因。下面的监控复制延迟时间部分介绍了这些指标。

更快的副本配置

您可以通过以下两种方式使 MySQL 副本更快地应用更改。用户可以使用以下选项来配置其副本:

  • 并行复制
  • 高性能 flush

并行复制

并行复制可能会将副本配置为使用多个并行操作以对副本应用更改,从而有助于改善复制延迟情况。如需了解如何使用并行复制,请参阅配置并行复制

高性能 flush

默认情况下,Cloud SQL for MySQL 会在每次事务后将重做日志 flush 到磁盘。高性能 flush 会将重做日志 flush 到磁盘的频率降低到每秒一次,从而提高写入性能。

将读取副本上的 innodb_flush_log_at_trx_commit 标志设置为 2。您还必须将 sync_binlog 标志设置为较高的值以让 innodb_flush_log_at_trx_commit 标志生效。

如需详细了解此标志,请参阅关于使用标志的提示

在读取副本上设置了 innodb_flush_log_at_trx_commit 标志并且 Cloud SQL 检测到可能发生崩溃时,Cloud SQL 会自动重新创建副本。

优化查询和架构

本部分建议一些可用于提高复制性能的常见查询和架构优化。

读取副本中的查询隔离级别

REPEATABLE READSERIALIZABLE 事务隔离级别会获取可能会阻止复制更改的锁定。请考虑降低副本中查询的隔离级别。READ COMMITTED 事务隔离级别可能表现更好。

主数据库中长时间运行的事务

如果单个事务中更新了大量行,则可能会导致更改数量突然激增(这些更改需要应用到主实例并随后发送到副本)。这适用于同时影响多行的单语句更新或删除。更改会在提交后发送到副本。如果副本上的查询负载也很高,则在该副本中应用的更改数突然增加可能会增加副本中锁定争用的可能性,从而导致复制延迟。

请考虑将大型事务拆分为多个较小的事务。

缺少主键

Cloud SQL 读取副本使用基于行的复制功能;如果复制的 MySQL 表没有主键,则复制性能不佳。我们建议所有复制的表都有主键。

对于 MySQL 8 或更高版本,我们建议您将标志 sql_require_primary_key 设置为 ON 以要求数据库中的表具有主键。

DDL 导致的独占锁定

数据定义语言 (DDL) 命令(例如 ALTER TABLECREATE INDEX)可能会导致副本因独占锁定而出现复制延迟。为避免锁定争用,请考虑在副本上的查询负载较低期间安排 DDL 执行。

过载的副本

如果读取副本收到的查询过多,则系统可能会阻止复制。请考虑在多个副本之间拆分读取,以减少每个副本的负载。

为了避免查询高峰,请考虑在应用逻辑或代理层(如果使用代理层)中限制副本读取查询。

如果主实例上出现活动峰值,请考虑分散更新。

单体式主数据库

请考虑将主数据库垂直(或水平)分片,以防止一个或多个滞后表阻止其他所有表。

监控复制延迟

您可以使用 replica_lagnetwork_lag 指标来监控复制延迟,并确定延迟原因在于主数据库、网络还是副本。

指标说明
复制延迟
(cloudsql.googleapis.com/database/replication/replica_lag)

副本状态晚于主实例状态的秒数。这是当前时间与主数据库提交当前应用于副本的事务的原始时间戳之间的差值。具体而言,如果副本尚未将写入应用于数据库,则即使它们接收了写入,写入操作也可能被视为滞后。

当副本在副本上运行 SHOW SLAVE STATUS 时,该指标会报告 Seconds_Behind_Master 的值。如需了解详情,请参阅《MySQL 参考手册》中的检查复制状态

最后一个 I/O 线程错误编号
(cloudsql.googleapis.com/database/mysql/replication/last_io_errno)

表示导致 I/O 线程失败的最后一个错误。如果此为非零值,则复制将中断。虽然这种情况极少见,但是也有发生的可能。查看 MySQL 文档以了解错误代码的含义。例如,主实例中的 binlog 文件可能在副本接收它们之前就被删除了。如果复制中断,Cloud SQL 通常会自动重新创建副本。此 last_io_errno 指标可能会告诉您原因。

最后一个 SQL 线程错误编号
(cloudsql.googleapis.com/database/mysql/replication/last_sql_errno)

表示导致 SQL 线程失败的最后一个错误。如果此为非零值,则复制将中断。虽然这种情况极少见,但是也有发生的可能。查看 MySQL 文档以了解错误代码的含义。如果复制中断,Cloud SQL 通常会自动重新创建副本。此 last_sql_errno 指标可以告诉您原因。

网络延迟
(cloudsql.googleapis.com/database/replication/network_lag)

从在主数据库中写入二进制日志到抵达副本中的 IO 线程所花费的时间(以秒为单位)。

如果 network_lag 为零或可以忽略,但 replica_lag 较高,则表示 SQL 线程应用复制更改的速度不够快。

验证复制

如需验证复制是否正常工作,请对副本运行以下语句:

mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
               Slave_IO_State: Queueing master event to the relay log
                  Master_Host: xx.xxx.xxx.xxx
                  Master_User: cloudsqlreplica
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.199927
          Read_Master_Log_Pos: 83711956
               Relay_Log_File: relay-log.000025
                Relay_Log_Pos: 24214376
        Relay_Master_Log_File: mysql-bin.199898
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 24214163
              Relay_Log_Space: 3128686571
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: Yes
           Master_SSL_CA_File: master_server_ca.pem
           Master_SSL_CA_Path: /mysql/datadir
              Master_SSL_Cert: replica_cert.pem
            Master_SSL_Cipher:
               Master_SSL_Key: replica_pkey.pem
        Seconds_Behind_Master: 2627
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 321071839
                  Master_UUID: 437d04e9-8456-11e8-b13d-42010a80027b
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: System lock
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set: 437d04e9-8456-11e8-b13d-42010a80027b:52111095710-52120776390
            Executed_Gtid_Set: 437d04e9-8456-11e8-b13d-42010a80027b:1-52113039508
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

如果正在进行复制,则 Slave_IO_State(第一列)显示 Waiting for master to send event 或类似消息。此外,Last_IO_Error 字段为空。

如果没有进行复制,则 Slave_IO_State 列显示状态 Connecting to masterLast_IO_Error 列显示状态 error connecting to master cloudsqlreplica@x.x.x.x:3306

根据 MySQL 文档,与复制延迟相关的一些其他字段如下:

字段说明
Master_Log_File
I/O 线程当前正在读取的源二进制日志文件的名称。
Read_Master_Log_Pos
I/O 线程已读取的当前源二进制日志文件中的位置。
Relay_Log_File
SQL 线程当前正在读取和执行的中继日志文件的名称。
Relay_Log_Pos
SQL 线程已读取和执行的当前中继日志文件中的位置。
Relay_Master_Log_File
包含 SQL 线程执行的最新事件的源二进制日志文件的名称。

在上面的示例中,Relay_Master_Log_File 的值为 mysql-bin.199898Master_Log_File 的值为 mysql-bin.199927。数字后缀 199898 小于 199927。也就是说,即使副本收到了较新的 mysql-bin.199927 日志文件,它仍会应用旧的 mysql-bin.199898

在此示例中,副本中的 SQL 线程有所延迟。

您还可以连接到主数据库并执行以下命令:

SHOW MASTER STATUS;

此命令显示正在主数据库中写入的 binlog 文件。

如果主数据库二进制日志文件比副本中的 Master_Log_File 新,则表示 I/O 线程滞后。副本仍在从主数据库中读取较旧的二进制日志文件。

如果 I/O 线程有所延迟,则 network_lag 指标也较高。如果 SQL 线程有所延迟,但 I/O 线程没有延迟,则 network_lag 指标不高,但 replica_lag 较高。

前面的命令可让您在延迟发生时观察延迟详情,而指标 network_lagreplica_lag 可让您查看延迟的过往情况。