复制延迟时间

本页面介绍如何排查和修复 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 可让您查看延迟的过往情况。

重新创建延迟副本

当复制落后于可接受的时间长度时,请重新创建延迟副本。

使用 Cloud SQL 时,您可以将读取副本配置为在以下情况下重新创建自身:复制延迟超过可接受的时间长度,并且延迟至少持续五分钟。

如果您将可接受的复制延迟定义为小于 360 秒(6 分钟),当至少 361 秒的复制延迟持续超过五分钟后,主实例会创建自身的新快照,并使用此快照重新创建读取副本。

重新创建延迟读取副本有以下好处:

  • 您可以控制可接受的复制延迟范围。
  • 您可以将排查复制延迟问题所花费的时间缩短数小时甚至数天。

其他功能详情包括:

  • 与以下版本兼容:
    • MySQL 5.7
    • MySQL 8.0
    • MySQL 8.4
  • 复制延迟时间的可接受范围必须以秒为单位来指定。
  • 可接受的最小值为 300 秒,即五分钟。
  • 可接受的最大值为 31,536,000 秒,即一年。
    • 如果您为实例启用重新创建延迟副本,但未设置可接受的最大复制延迟时间,则 Cloud SQL 会使用默认值一年。
  • 支持的虚拟机类型:
    • 读取副本
    • 跨区域读取副本
    • 级联副本
  • replicationLagMaxSeconds 字段设置的值只应用于一个副本实例。如果主实例有多个副本实例,则可以为每个副本设置不同的值。
  • 在重新创建副本期间,当以下操作完成时,可能会有一些停机时间:
    • 停止复制。
    • 删除副本。
    • 创建主实例的快照。
    • 根据此最新快照重新创建副本。新副本使用与之前的副本相同的名称和 IP 地址。因此,MySQL 必须停止并重启。
    • 新副本开始复制数据。
  • replicationLagMaxSeconds 是实例级字段。每个实例都有自己的值。
  • 如果一个主实例有多个读取副本,您可以为每个副本的 replicationLagMaxSeconds 字段设置唯一值。

    为不同的副本指定不同的时间阈值有助于避免所有副本同时停止工作。

启用重新创建延迟副本

重新创建延迟副本功能默认处于停用状态。如需在创建实例时启用该功能,请使用以下方法之一:

gcloud

使用 gcloud sql instances create 命令创建新的读取副本实例,带上
--replication-lag-max-seconds-for-recreate 标志:

gcloud beta sql instances create REPLICA_INSTANCE_NAME \
  --master-instance-name=PRIMARY_INSTANCE_NAME \
  --database-version=DATABASE_VERSION \
  --tier=TIER \
  --edition=EDITION \
  --region=REGION \
  --root-password=PASSWORD \
  --replication-lag-max-seconds-for-recreate=REPLICATION_LAG_MAX_SECONDS

其中:

  • REPLICA_INSTANCE_NAME 是副本实例的名称。
  • PRIMARY_INSTANCE_NAME 是主实例的名称。
  • DATABASE_VERSION 是实例的数据库版本。例如 MYSQL_8_0_31
  • TIER 是您要为副本实例使用的机器类型。例如 db-perf-optimized-N-4。如需了解详情,请参阅自定义实例配置
  • EDITION 是您要为副本实例使用的版本。例如 ENTERPRISE_PLUS。如需了解详情,请参阅创建实例
  • REGION 是您要为副本实例使用的区域。例如 us-central1
  • PASSWORD 是实例的 root 密码。
  • REPLICATION_LAG_MAX_SECONDS 是可接受的最大复制延迟时间(以秒为单位)。例如 600。可接受的最小值为 300 秒,即五分钟。可接受的最大值为 31,536,000 秒,即一年。

REST API

replicationLagMaxSeconds 字段位于 DatabaseInstance 资源中。将此字段添加到请求正文中:

{
  "settings": {
  "replicationLagMaxSeconds" :REPLICATION_LAG_MAX_SECONDS,
  }
  ...
}

其中:

  • REPLICATION_LAG_MAX_SECONDS 是可接受的最大复制延迟时间(以秒为单位)。例如 600

更新复制延迟的重新创建时间范围

如需查看实例的设置,请使用查看实例摘要信息中所述的任意方法。

利用这些信息,您可以选择是否更新在重新创建副本之前可接受的复制延迟时间范围。

gcloud

使用 gcloud sql instances patch 命令更新根据复制延迟重新创建实例的时间范围:

gcloud beta sql instances patch INSTANCE_NAME \
  --replication-lag-max-seconds-for-recreate=REPLICATION_LAG_MAX_SECONDS

其中:

  • INSTANCE_NAME 是实例的名称。
  • REPLICATION_LAG_MAX_SECONDS 是可接受的最大复制延迟时间(以秒为单位)。例如 700。如果您想恢复为默认值一年,请输入 31536000。可接受的最小值为 300 秒,即五分钟。可接受的最大值为 31,536,000 秒,即一年。

REST API

您可以使用 instances.patchinstance.insert 更新该政策。

如需查看有关如何使用 REST API 更新设置的示例,请参阅修改实例

限制

重新创建延迟副本存在以下限制:

  • 只能以秒为单位设置 replicationLagMaxSeconds 的值。
  • 重新创建操作之前在读取副本上创建的索引将不会保留。如果存在索引,请在重新创建副本后创建二级索引。
  • 为避免读取副本频繁停机,每实例每天只能重新创建一次。
  • 此功能不支持高可用读取副本和外部服务器的副本。
  • 如果您在级联副本上启用重新创建延迟副本的功能,Cloud SQL 会先重新创建叶副本,以保持复制一致性。
  • 重新创建跨区域副本会产生额外的费用
  • 您无法在 Google Cloud 控制台中启用重新创建延迟副本的功能。

后续步骤: