AlloyDB 的架构可将计算和存储分离,从而使两者能够独立扩缩。虽然主实例和读取池实例共享相同的底层存储,但复制仍然是维护读取副本之间数据一致性和新鲜度的关键流程。在 AlloyDB 集群中,写入操作在主实例上执行,然后记录在共享存储空间中的预写式日志 (WAL) 中。然后,这些更改会复制到读取池实例的内存缓存中。了解此复制流程的两个主要步骤是排查任何问题的关键:
WAL 刷新:包含数据库更改的预写式日志 (WAL) 从主实例发送到副本。然后,副本会立即将 WAL 持久保存到磁盘。这两个步骤中的任何延迟都会导致复制延迟。不过,此术语可能存在歧义。更准确地说,我们可以将复制延迟细分为以下两个组成部分:
刷新或网络延迟:这是 WAL 刷新步骤中的延迟。是指从主实例发送 WAL 并将其持久保留在副本上所花费的时间。
重放延迟时间:这是 WAL 应用步骤中的延迟时间。是指副本应用来自 WAL 的更改所需的时间。
您是必须更关注刷新延迟还是重放延迟,取决于您的使用场景:
- 如果您担心数据丢失(例如,使用跨区域副本时),则必须密切关注刷新延迟。如果 WAL 尚未在副本上持久保留,并且主实例崩溃,则从副本的角度来看,更改会丢失。
- 如果您担心读取副本上的数据新鲜度,则必须密切关注重放延迟。重放延迟时间较长意味着,读取副本上的数据已过时。
检查是否存在复制延迟
您可以在 Google Cloud 控制台中监控读取池实例的复制延迟。如需了解详情,请参阅监控实例。您还可以使用创建指标阈值提醒政策,监控读取池复制延迟并在达到指定的阈值时收到提醒。
复制延迟的常见原因
以下列出了复制延迟的一些常见原因以及相应的解决方法。
资源争用
对 CPU 和内存等系统资源的争用也可能会减慢复制速度。
- CPU 和内存压力:读取池实例上的繁重读取工作负载可能会与复制进程争用 CPU 和内存资源。您可以在 Google Cloud 控制台中查看实例的 CPU 和内存用量。如果您发现资源利用率很高,可能需要纵向扩容或横向扩容读取池实例。
- 读取池节点大小:如果主实例远大于读取池节点,则主实例生成复制日志的速度可能会比读取节点处理复制日志的速度更快。在这种情况下,建议使用较大的读取节点,以便为副本提供更多资源。
复制冲突
读取查询有时会阻止复制过程,因为它们会占用复制过程正在等待的资源。例如,如果读取查询锁定了复制进程需要更新的数据库对象,则复制会一直处于阻塞状态,直到该锁定被释放。这些冲突称为“缓冲区锁定冲突”。
您可以在 Logs Explorer 中查看 postgres.log 文件,以查找 canceling statement due to conflict with recovery 消息,从而确定这些冲突。
如需缓解复制冲突,您可以执行以下操作:
减少
max_standby_streaming_delay:此参数用于确定复制进程在取消阻碍复制的查询之前等待的时间。默认值是 30 秒。降低此值有助于减少复制延迟,但也可能会导致更多读取查询被取消。您可以调整此参数,为应用找到最佳平衡点。避免长时间运行的查询:读取池中长时间运行的查询可能会增加复制冲突的可能性。考虑将长时间运行的查询移至复制延迟时间要求不高的其他读取池。
启用
alloydb.promote_cancel_to_terminate:此标志默认处于启用状态,可让 AlloyDB 强制终止对取消请求无响应的查询后端。这有助于防止无响应的后端长时间阻止复制。
临时读取查询限制
AlloyDB 还允许您使用标志 google_storage.log_replay_throttle_read_transactions 控制是否在读取节点上启用基于延迟的读取查询节流。如果该参数设置为默认值 on,则当复制延迟超过 1 秒时,系统会暂停启动新查询并读取新缓冲区,从而限制读取查询,暂停时间最长为 1 分钟。此功能通过为重放提供更多资源来更快地赶上进度,从而缩短复制延迟时间,但可能会增加读取延迟时间。如果您的应用对复制延迟不敏感,则可以通过将 google_storage.log_replay_throttle_read_transactions 设置为 off 来优先缩短读取查询延迟时间。
您可以使用以下方法监控查询限制的影响:
日志:在 Logs Explorer 中搜索
postgres.log文件中的Delayed.*due to replica lag消息,以确定因副本延迟而导致查询延迟的时间。Cloud Monitoring:使用
alloydb.googleapis.com/instance/postgresql/wait_count指标查看有多少查询受到限制。为此,请按wait_event_name过滤相应指标,然后查找HighLagThrottle。如需查看查询受到限制的总时间,您可以使用具有相同过滤条件的alloydb.googleapis.com/instance/postgresql/wait_time指标。如需了解详情,请参阅系统分析洞见指标参考文档。Query Insights:在 Query Insights 信息中心内,如果查询因复制延迟而受到限制,活跃查询视图的等待事件列中会显示
HighLagThrottle等待事件。如需了解详情,请参阅监控活跃查询。
繁重的工作负载
主实例上的写入工作负载突然增加可能会生成大量复制日志,这可能会使读取池实例不堪重负,并导致复制延迟。您可以在 Google Cloud 控制台中监控主实例上的写入流量。
大额交易
大型事务(例如影响大量行的 COMMIT 或 ABORT 记录)可能需要很长时间才能复制到读取池实例。在 PostgreSQL 14 中,持有长列表排他锁的长时间运行的事务可能会导致读取副本的内存用量增加,最终可能会导致读取池实例崩溃。
为缓解此问题,您可以终止主实例上长时间运行的事务。
排查阻止复制的问题
在出现复制延迟之前,您必须拥有一个正常运行的读取池。以下问题可能会完全阻止复制,方法是阻止创建读取池或导致读取副本崩溃。
读取池创建问题
如果读取池创建失败,您可能会在 Cloud Logging 中的 AlloyDB 日志中看到 Failed to create read pool 消息。如果集群已达到存储空间上限,导致主实例无法分配更多空间,则可能会发生这种情况。虽然 AlloyDB 会自动扩缩存储空间,但您可能需要调查哪些内容占用了存储空间并删除不必要的数据,或者与支持团队联系以请求增加存储空间配额。
读取池实例崩溃
在 PostgreSQL 14 中,主实例上持有大量排他锁的长时间运行的事务可能会导致只读副本的内存用量增加,最终可能会导致读取池实例崩溃。
为缓解此问题,您可以终止主实例上长时间运行的事务。
调整实例大小对复制延迟时间的影响
AlloyDB 的存储架构可确保读取池刷新延迟不受实例大小调整的影响。不过,重放功能不适用此规则。复制件的回放能力取决于其负载。如果您更新实例配置(例如调整实例大小),则副本在操作完成后可能无法完全预热缓存,具体取决于工作负载。这意味着,对于尚未缓存的记录,重放或处理速度会较慢。在这种情况下,这可能意味着重放延迟会暂时增加。