在查询 RDS for PostgreSQL 数据库实例的只读副本时,如何排除错误“由于与恢复冲突而取消语句”?

2 分钟阅读
0

我已经为 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 实例创建只读副本。当我查询此只读副本时,出现错误“由于与恢复冲突而取消语句”。

简短描述

发生此错误的原因可能是主实例对只读副本上发生的活动缺乏可见性。无法将 WAL 信息应用于只读副本时,就会发生恢复冲突,因为这些更改可能会阻碍只读副本上正在发生的活动。

例如,假设在主实例中已删除表的只读副本上执行长时间运行的 SELECT 语句时,您在主实例上运行了 DROP 语句。然后,只读副本有两个选项:

  • 等待 SELECT 语句完成后再应用 WAL 记录。在此情况下,复制滞后会增加。
  • 应用 WAL 记录,然后取消 SELECT 语句。在此情况下,您会收到错误“由于与恢复冲突而取消语句”。

只读副本根据参数 max_standby_streaming_delaymax_standby_archive_delay 的值来解决这些复制冲突。max_standby_streaming_delay 参数确定只读副本在取消与即将应用的 WAL 条目冲突的备用查询之前必须等待多长时间。如果冲突语句在此时间段之后仍在运行,则 PostgreSQL 将取消该语句并发出以下错误消息:

ERROR: canceling statement due to conflict with recovery

出现此错误通常是由于在只读副本上长时间运行查询。

在前面运行 DROP 语句的示例中,DROP 请求存储在 WAL 文件中,以便稍后在只读副本上应用以保持一致性。假设只读副本上已经运行一条 SELECT 语句,该语句尝试从已删除的对象中检索数据,其运行时间大于 max_standby_streaming_delay 中的值。然后,将取消 SELECT 语句,以便应用 DROP 语句。

会话 1(只读副本)在 example_table 上运行 SELECT语句:

postgres=> SELECT * from example_table;

会话 2(主实例)在 example_table 上运行 DROP 语句:

postgres=> DROP TABLE example_table;

您收到以下错误:

postgres@postgres:[27544]:ERROR:  canceling statement due to conflict with recovery
postgres@postgres:[27544]:DETAIL:  User was holding a relation lock for too long.
postgres@postgres:[27544]:STATEMENT:  select * from example_table;

此外,当只读副本上的事务正在读取主实例上设置为删除的元组时,可能会发生查询冲突。删除元组,然后在主实例上执行清理操作,这会导致与仍在副本上运行的 SELECT 查询发生冲突。在此情况下,副本上的 SELECT 查询将终止,并显示以下错误消息:

ERROR:  canceling statement due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.

解决方案

当只读副本遇到冲突,并且在错误日志中收到“由于与恢复冲突而导致取消语句”错误时,您可以根据错误消息设置某些自定义参数,以减少冲突的影响。请注意,必须在只读副本上设置自定义参数。

您会收到错误“由于与恢复冲突而取消语句”和“详细信息:用户持有关系锁的时间过长”

max_standby_streaming_delay/max_standby_archive_delay:您可以使用这些参数在取消与即将应用的 WAL 条目冲突的备用语句之前留出更多时间。这些值表示从主实例收到数据后允许应用 WAL 数据的总时间。这些参数的指定取决于从何处读取 WAL 数据。如果从流式传输复制中读取 WAL 数据,则使用 max_standby_streaming_delay 参数。如果从 Amazon Simple Storage Service (Amazon S3) 中的存档位置读取 WAL 数据,则使用 max_standby_archive_delay 参数。

设置这些参数时,请记住以下几点:

  • 如果将这些参数的值设置为 -1,则允许副本实例永远等待冲突查询完成,从而增加复制滞后。
  • 如果将这些参数的值设置为 0,则会取消冲突的查询,并将 WAL 条目应用于副本实例。
  • 这些参数的默认值设置为 30 秒。
  • 如果在设置这些参数时未指定单位,则以毫秒为单位。

根据您的使用案例调整这些参数的值,以平衡查询取消或复制滞后。

**注意:**如果正在增加 max_standby_archive_delay 以避免取消与读取 WAL 存档条目冲突的查询,那么也要考虑增加 max_standby_streaming_delay 以避免与流式传输 WAL 条目冲突相关的取消。

您会收到错误“由于与恢复冲突而取消语句”和“详细信息:查看必须删除的行版本可能需要执行用户查询”

hot_standby_feedback:如果激活此参数,则会从只读副本向主实例发送反馈消息,其中包含最早的活动事务的信息。因此,主实例不会删除事务可能需要的记录。

当您在只读副本上激活此参数时,长时间运行的只读副本查询可能会导致主实例上的表膨胀。这是因为清理操作不会移除只读副本上运行的查询可能需要的死元组。默认情况下,此参数处于关闭状态。因此,激活此参数时务必小心。

您还可以检查只读副本上的 pg_stat_database_conflicts 视图,了解由于与只读副本上恢复冲突而取消的语句的统计信息。


AWS 官方
AWS 官方已更新 2 年前