在 RDS for PostgreSQL 中解除可识别的真空拦截器 - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

在 RDS for PostgreSQL 中解除可识别的真空拦截器

自动真空会执行积极真空操作,并将事务 ID 的龄期降低到低于由 RDS 实例的 autovacuum_freeze_max_age 参数指定的阈值。您可以使用 Amazon CloudWatch 指标 MaximumUsedTransactionIDs 跟踪此龄期。

要查找 Amazon RDS 实例的 autovacuum_freeze_max_age 设置(默认为 2 亿个事务 ID),您可以使用以下查询:

SELECT TO_CHAR(setting::bigint, 'FM9,999,999,999') autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age';

请注意,postgres_get_av_diag() 仅在龄期超过 Amazon RDS 的 5 亿个事务 ID 的自适应自动真空阈值时检查积极真空拦截器。要使 postgres_get_av_diag() 检测拦截器,拦截器必须至少有 5 亿个事务。

postgres_get_av_diag() 函数可识别以下类型的拦截器:

活动语句

在 PostgreSQL 中,活动语句是数据库当前正在执行的 SQL 语句。这包括查询、事务或任何正在进行的操作。通过 pg_stat_activity 进行监控时,状态列指示具有相应 PID 的进程处于活动状态。

postgres_get_av_diag() 函数在识别系活动语句的语句时会显示类似于以下内容的输出。

blocker | Active statement database | my_database blocker_identifier | SELECT pg_sleep(20000); wait_event | Timeout:PgSleep autovacuum_lagging_by | 568,600,871 suggestion | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. suggested_action | {"SELECT pg_terminate_backend (29621);"}

建议采取的措施

按照 suggestion 列中的指导,用户可以连接到存在活动语句的数据库,并按照 suggested_action 列中的指定,建议仔细查看终止会话的选项。如果终止是安全的,则可以使用 pg_terminate_backend() 函数终止会话。此操作可由管理员(如 RDS 主账户)或具有所需 pg_terminate_backend() 权限的用户执行。

警告

已终止的会话将撤消 (ROLLBACK) 其所做的更改。根据您的要求,您可能需要重新运行相应语句。但是,建议只有在自动真空过程完成其积极真空操作之后才这样做。

事务中空闲

事务中空闲语句是指已打开显式事务(例如通过发出 BEGIN 语句)、执行了一些工作,并且现在正在等待客户端传递更多工作或通过发出 COMMITROLLBACKEND(这将导致隐式 COMMIT)来发出事务结束信号的任何会话。

postgres_get_av_diag() 函数在将 idle in transaction 语句识别为拦截器时,显示类似于以下内容的输出。

blocker | idle in transaction database | my_database blocker_identifier | INSERT INTO tt SELECT * FROM tt; wait_event | Client:ClientRead autovacuum_lagging_by | 1,237,201,759 suggestion | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. suggested_action | {"SELECT pg_terminate_backend (28438);"}

建议采取的措施

suggestion 列中所示,您可以连接到存在事务中空闲会话的数据库,并使用 pg_terminate_backend() 函数终止会话。该用户可以是您的管理员(RDS 主账户)用户或具有 pg_terminate_backend() 权限的用户。

警告

已终止的会话将撤消 (ROLLBACK) 其所做的更改。根据您的要求,您可能需要重新运行相应语句。但是,建议只有在自动真空过程完成其积极真空操作之后才这样做。

准备好的事务

PostgreSQL 允许属于称为准备好的事务的两阶段提交策略一部分的事务。通过将 max_prepared_transactions 参数设置为非零值即可启用这些功能。准备好的事务旨在确保事务的持久性,即使在数据库崩溃、重启或客户端断开连接后仍可用。与定期事务一样,它们会被分配一个事务 ID,并且可能会影响自动真空。如果保持已准备状态,则自动真空将无法执行冻结,这样可能会导致事务 ID 重叠。

当事务被无限期地准备而没有被事务管理器解决时,它们将成为孤立的已准备事务。解决此问题的唯一方法是分别使用 COMMIT PREPAREDROLLBACK PREPARED 命令提交或回滚事务。

注意

请注意,在准备事务期间进行的备份在还原后仍将包含该事务。有关如何查找和关闭此类事务的信息,请参阅以下信息。

postgres_get_av_diag() 函数在识别出系已准备事务的拦截器时显示以下输出。

blocker | Prepared transaction database | my_database blocker_identifier | myptx wait_event | Not applicable autovacuum_lagging_by | 1,805,802,632 suggestion | Connect to database "my_database" and consider either COMMIT or ROLLBACK the prepared transaction using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. suggested_action | {"COMMIT PREPARED 'myptx';",[OR],"ROLLBACK PREPARED 'myptx';"}

建议采取的措施

如建议列中所述,连接到已准备事务所在的数据库。根据 suggested_action 列,仔细查看是执行 COMMIT 还是 ROLLBACK,并执行适当的操作。

为了总体上监控已准备事务,PostgreSQL 提供了一个名为 pg_prepared_xacts 的目录视图。您可以使用以下查询来查找已准备事务。

SELECT gid, prepared, owner, database, transaction AS oldest_xmin FROM pg_prepared_xacts ORDER BY age(transaction) DESC;

逻辑复制槽

复制槽的用途是保存未使用的更改,直到它们被复制到目标服务器。有关更多信息,请参阅 PostgreSQL 的 Logical replication

有两种类型的逻辑复制槽。

非活动逻辑复制槽

复制终止后,无法删除未使用的事务日志,且复制槽变为非活动状态。尽管订阅用户当前未使用非活动逻辑复制槽,但它仍保留在服务器上,从而保留 WAL 文件并防止删除旧的事务日志。这样会增加磁盘使用量,特别是阻止自动真空清理内部目录表,因为系统必须保护 LSN 信息不被覆盖。如果不加以解决,可能会导致目录臃肿、性能下降和重叠真空风险增加,从而可能导致事务停机。

活动但速度较慢的逻辑复制槽

有时,由于逻辑复制的性能下降,目录中无效元组的删除会延迟。这种复制延迟会减慢 catalog_xmin 的更新速度,并可能导致目录臃肿和重叠真空。

postgres_get_av_diag() 函数在找到逻辑复制槽作为拦截器时,会显示类似于以下内容的输出。

blocker | Logical replication slot database | my_database blocker_identifier | slot1 wait_event | Not applicable autovacuum_lagging_by | 1,940,103,068 suggestion | Ensure replication is active and resolve any lag for the slot if active. If inactive, consider dropping it using the command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. suggested_action | {"SELECT pg_drop_replication_slot('slot1') FROM pg_replication_slots WHERE active = 'f';"}

建议采取的措施

要解决此问题,请检查复制配置中是否存在可能终止应用进程的目标架构或数据问题。最常见的原因如下:

  • 缺少列

  • 数据类型不兼容

  • 数据不匹配

  • 缺少表

如果该问题与基础设施问题有关:

如果您的实例位于 Amazon 网络之外或 Amazon EC2 上,请咨询您的管理员,了解如何解决可用性或基础设施相关问题。

删除非活动槽

警告

注意:在删除复制槽之前,请仔细确保其没有正在进行的复制、处于非活动状态且处于不可恢复状态。过早删除槽可能会中断复制或导致数据丢失。

确认不再需要复制槽后,将其删除以允许自动真空继续运行。条件 active = 'f' 可确保仅删除非活动槽。

SELECT pg_drop_replication_slot('slot1') WHERE active ='f'

只读副本

Amazon RDS 只读副本启用 hot_standby_feedback 设置后,它会阻止主数据库上的自动真空删除只读副本上运行的查询可能仍需要的死行。这样会影响所有类型的物理只读副本,包括那些带有或不带由复制槽管理的只读副本。此行为是必需的,因为在备用副本上运行的查询要求这些行在主副本上保持可用,从而防止发生查询冲突和取消。

带有物理复制槽的只读副本

带有物理复制槽的只读副本可显著增强 RDS for PostgreSQL 中复制的可靠性和稳定性。这些槽可确保主数据库保留基本的预写日志文件,直到副本处理它们,即使在网络中断期间也能保持数据一致性。

从 RDS for PostgreSQL 版本 14 开始,所有副本均使用复制槽。在早期版本中,只有跨区域副本使用复制槽。

postgres_get_av_diag() 函数在找到以物理复制槽作为拦截器的只读副本时,会显示类似于以下内容的输出。

blocker | Read replica with physical replication slot database | blocker_identifier | rds_us_west_2_db_xxxxxxxxxxxxxxxxxxxxx wait_event | Not applicable autovacuum_lagging_by | 554,080,689 suggestion | Run the following query on the replica "rds_us_west_2_db_xxxxxxxxxxxxxxxxxxxx" to find the long running query: | SELECT * FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 757989377; | Review carefully and you may consdier terminating the query on read replica using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. + | suggested_action | {"SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 757989377;"," + | [OR] + | ","Disable hot_standby_feedback"," + | [OR] + | ","Delete the read replica if not needed"}
使用流式复制的只读副本

Amazon RDS 允许在较旧版本(最高为版本 13)中设置不带物理复制槽的只读副本。这种方法通过允许主数据库更积极地回收 WAL 文件来减少开销,这在磁盘空间有限的环境中是有利的,并可以容忍偶尔发生的 ReplicaLag。但是,如果没有槽,备用副本必须保持同步,以免丢失 WAL 文件。Amazon RDS 使用已存档的 WAL 文件来帮助副本在落后时赶上,但是此过程需要仔细监控,而且可能速度很慢。

postgres_get_av_diag() 函数在找到作为拦截器的流式只读副本时,会显示类似于以下内容的输出。

blocker | Read replica with streaming replication slot database | Not applicable blocker_identifier | xx.x.x.xxx/xx wait_event | Not applicable autovacuum_lagging_by | 610,146,760 suggestion | Run the following query on the replica "xx.x.x.xxx" to find the long running query: + | SELECT * FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 348319343; + | Review carefully and you may consdier terminating the query on read replica using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. + | suggested_action | {"SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 348319343;"," + | [OR] + | ","Disable hot_standby_feedback"," + | [OR] + | ","Delete the read replica if not needed"}

建议采取的措施

按照 suggested_action 列中的建议,仔细查看用于解除阻止自动真空的这些选项。

  • 终止查询 – 按照建议列中的指导,您可以连接到只读副本,如 suggested_action 列中指定,建议仔细查看终止会话的选项。如果终止被视为是安全的,则可以使用 pg_terminate_backend() 函数终止会话。此操作可由管理员(如 RDS 主账户)或具有所需 pg_terminate_backend() 权限的用户执行。

    您可以在只读副本上运行以下 SQL 命令来终止用于阻止主数据库上的真空清理旧行的查询。在函数的输出中报告 backend_xmin 的值:

    SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = backend_xmin;
  • 禁用热备用反馈 – 如果 hot_standby_feedback 参数会导致明显的真空延迟,请考虑禁用该参数。

    hot_standby_feedback 参数允许只读副本将其查询活动通知主数据库,从而防止主数据库对备用数据库上使用的表或行执行清理操作。虽然这样可以确保备用数据库上的查询稳定性,但它可能会显著延迟主数据库上的清理时间。禁用此功能允许主数据库继续进行清理,而无需等待备用数据库赶上。但是,如果备用数据库尝试访问已被主数据库清理的行,则可能导致备用数据库上的查询取消或失败。

  • 如果不需要只读副本,请将其删除 – 如果不再需要只读副本,则可以将其删除。这将消除相关的复制开销,并允许主数据库在不受副本阻碍的情况下回收事务日志。

临时表

使用 TEMPORARY 关键字创建的临时表驻留在临时架构中,例如 pg_temp_xxx,并且只能由创建它们的会话访问。会话结束时会删除临时表。但是,这些表对于 PostgreSQL 的自动真空流程是不可见的,必须由创建它们的会话手动清理。尝试从另一个会话中清空临时表是无效的。

在特殊情况下,存在一个临时表,但没有活动会话拥有该表。如果所属会话由于致命崩溃、网络问题或类似事件而意外结束,则可能无法清理临时表,从而会将其留作为“孤立”表。当 PostgreSQL 自动真空进程检测到孤立的临时表时,它会记录以下消息:

LOG: autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"

postgres_get_av_diag() 函数在将临时表识别为拦截器时,会显示类似于以下内容的输出。要使该函数正确显示与临时表相关的输出,需要在存在这些表的同一数据库中执行该函数。

blocker | Temporary table database | my_database blocker_identifier | pg_temp_14.ttemp wait_event | Not applicable autovacuum_lagging_by | 1,805,802,632 suggestion | Connect to database "my_database". Review carefully, you may consider dropping temporary table using command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide. suggested_action | {"DROP TABLE ttemp;"}

建议采取的措施

按照输出的 suggestion 列中提供的说明识别并删除阻止自动真空运行的临时表。使用以下命令删除由 postgres_get_av_diag() 报告的临时表。根据 postgres_get_av_diag() 函数提供的输出替换表名称。

DROP TABLE my_temp_schema.my_temp_table;

以下查询可用于识别临时表:

SELECT oid, relname, relnamespace::regnamespace, age(relfrozenxid) FROM pg_class WHERE relpersistence = 't' ORDER BY age(relfrozenxid) DESC;