复制延迟

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

概览

Cloud SQL 读取副本使用 PostgreSQL 流式复制功能。更改会写入主实例中的预写式日志 (WAL)。 WAL 发送者将 WAL 发送到副本中的 WAL 接收者,在其中应用它们。

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

  • 主实例将更改发送到副本的速度不够快。
  • 副本接收更改的速度不够快。
  • 副本无应用更改的速度不够快。
您可以使用 network_lag 指标监控上述前两个原因。第三个原因通过 replica_lag 指标观察。replica_lag 高表示副本无法足够快速地应用复制更改。您可以通过 replica_byte_lag 指标观察总延迟,该指标具有指示更多详情的标签。下面的监控复制延迟时间部分介绍了这些指标。

优化查询和架构

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

读取副本中长时间运行的查询

副本中的长时间运行的查询可能会阻止 Cloud SQL 的复制。您可能希望使用单独的副本进行在线事务处理 (OLTP) 和在线分析处理 (OLAP),并且仅将长时间运行的查询发送到 OLAP 副本。

请考虑调整副本的 max_standby_archive_delaymax_standby_streaming_delay 标志。

如果您怀疑 VACUUM 是问题所在,并且不接受查询取消,请考虑在副本中设置 hot_standby_feedback 标志。

如需了解详情,请参阅 PostgreSQL 热备用文档

DDL 导致的独占锁定

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

如需了解详情,请参阅 PostgreSQL 热备用文档

过载的副本

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

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

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

单体式主数据库

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

监控复制延迟

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

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

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

此指标是使用副本中的 now() - pg_last_xact_replay_timestamp() 计算的。这是一个近似值。如果复制中断,则副本不知道主数据库的进度,并且此指标不会指示总延迟。

延迟字节数
(cloudsql.googleapis.com/database/postgres/replication/replica_byte_lag)

副本状态滞后于主数据库状态的字节数。replica_byte_lag 会导出 4 个时序,replica_lag_type 标签可以表示以下任意一项:

  • sent_location:表示已生成但尚未发送到副本的 WAL 字节数。
  • write_location:写入字节数减去发送延迟字节数表示网络中已发出但尚未在副本中写入的 WAL 字节数。
  • flush_location:Flush 字节数减去写入延迟字节数表示副本中已写入但尚未 flush 的 WAL 字节数。
  • replay_location:显示总延迟(以字节为单位)。重放减去清空延迟时间表示重放延迟时间。
网络延迟
(cloudsql.googleapis.com/database/replication/network_lag)

从在主数据库中提交到抵达副本中的 WAL 接收器所需的秒数。

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

验证复制

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

select status, last_msg_receipt_time from pg_stat_wal_receiver;

如果正在进行复制,您会看到状态 streaming 和最近的 last_msg_receipt_time:

postgres=> select status, last_msg_receipt_time from pg_stat_wal_receiver;
  status   |     last_msg_receipt_time
-----------+-------------------------------
 streaming | 2020-01-21 20:19:51.461535+00
(1 row)

如果未发生复制,则返回空结果:

postgres=> select status, last_msg_receipt_time from pg_stat_wal_receiver;
 status | last_msg_receipt_time
--------+-----------------------
(0 rows)