跳至内容

如何排查 autovaccum 在 Amazon RDS for PostgreSQL 或 Aurora PostgreSQL 兼容版数据库中触发 "to prevent wraparound"(“防止事务回卷”)标志的问题?

3 分钟阅读
0

我想解决 autovaccum 在 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 或 Amazon Aurora PostgreSQL 兼容版数据库中触发 "to prevent wraparound"(“防止事务回卷”)标志时的性能问题。

简短描述

当您查询 pg_stat_activity 时,autovacuum 可能会持续运行并触发 "to prevent wraparound"(“防止事务回卷”)标志。

autovacuum worker 通常不会阻止其他命令。当某个进程尝试获取与 autocvacuum 的 SHARE UPDATE EXCLUSIVE 锁相冲突的锁时,系统可能会中断 autovacuum。但是,当 autovacuum 为防止事务 ID 回卷而运行时,系统不会自动中断该进程。

在以下场景中,可能会触发带有 "to prevent wraparound"(“防止事务回卷”)标志的激进 autovacuum:

  • 表的 relfrozenxid 值超过了 vacuum_freeze_table_age 事务数,因此系统执行激进 vacuum 来冻结旧元组并推进 relfrozenxid。
  • 表达到了其 autovacuum_freeze_max_age 限制。

当 autovacuum 激进运行时,可能会出现数据库性能问题。有关更多信息,请参阅 PostgreSQL 网站上的 Automatic vacuuming。

解决方法

确定 autovacuum 是否正在运行

要确定 autovacuum 是否正在运行、运行多长时间或是否正在等待,请运行以下查询:

SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query  
FROM pg_stat_activity  
WHERE upper(query) LIKE '%VACUUM%'  
ORDER BY xact_start;

在以下输出示例中,带有 "to prevent wraparound"(“防止事务回卷”)标志的进程正在 mydb 的 mytable1 和 mytable2 上运行:

datname | usename  | pid   | state  | wait_event |       xact_runtime      | query  
--------+----------+-------+--------+------------+-------------------------+----------------------------------------------------------------------------------------------  
mydb    | rdsadmin | 16473 | active |            | 33 days 16:32:11.600656 | autovacuum: VACUUM ANALYZE public.mytable1 (to prevent wraparound)  
mydb    | rdsadmin | 22553 | active |            | 14 days 09:15:34.073141 | autovacuum: VACUUM ANALYZE public.mytable2 (to prevent wraparound)  
mydb    | rdsadmin | 41909 | active |            | 3 days 02:43:54.203349  | autovacuum: VACUUM ANALYZE public.mytable3  
mydb    | rdsadmin | 618   | active |            | 00:00:00                | SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query+  
        |          |       |        |            |                         | FROM pg_stat_activity +  
        |          |       |        |            |                         | WHERE query like '%VACUUM%'+  
        |          |       |        |            |                         | ORDER BY xact_start; +

若表的 relfrozenxid 超过 autovaccum_freeze_max_age 中的事务数量,autovaccum 就会锁定这些表。

识别未冻结的事务

要识别数据库中未冻结的事务,请运行以下查询:

SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) desc limit 20;

在以下输出示例中,autovacuum 守护进程会优先处理 datfrozenxid 超过 2 亿的数据库:

datname   | age  
mydb      | 1771757888  
template0 | 1721757888  
template1 | 1721757888  
rdsadmin  | 1694008527  
postgres  | 1693881061  
(5 rows)

数据库的 pg_database 行的 datfrozenxid 列位于数据库中正常事务 ID 的末尾。datfrozenxid 列是数据库内各表 relfrozenxid 的最小值。

冻结表

如果已达到 relfrozenxid 最大表年龄,请手动对表执行 vacuum 冻结操作。

手动执行 vacuum 冻结操作完成后,查看详细输出以确定是否存在阻止程序,例如旧复制槽和已准备事务。如果您收到 "DETAIL: xxx dead row versions cannot be removed yet, oldest xmin: xxx" 消息,则表示 vacuum 正在运行,但无法清理死元组。

要查找 vacuum 阻止程序,您可以使用 postgres_get_av_diag() 函数。有关更多信息,请参阅识别并解决 RDS for PostgreSQL 中的激进 vacuum 阻止程序。

增加 autovacuum worker 数量并移除未使用的索引

当需要执行 vacuum 操作的数据库或表超出 autovacuum_max_workers 配额时,引擎只有在 worker 可用时才会处理下一个数据库或表。在高事务率的环境中,vacuum 可能会出现事务回卷问题。

要解决此问题,请增大 autovacuum_max_workers 参数,以增加并行的 autovacuum worker。

如果您的表包含大型索引,最佳做法是移除未使用的索引。

增大 vacuum 内存

为确保引擎将调整后的内存分配应用于新的 autovacuum,请增大 autovacuum_work_mem 参数。

要为 vacuum 手动操作(例如 vacuum freeze)增加 maintenance_work_mem,请运行以下命令:

SET maintenance_work_mem TO '2GB';

**注意:**maintenance_work_mem 的默认值为 64MB。vacuum 完成后,请将该值更改回先前的值。如果不更改该值,则规格较小的实例可能会出现内存问题。

要启动 vacuum 操作,请运行以下命令:

VACUUM FREEZE VERBOSE table_name;

如果存在需要清理的大型索引,则 autovacuum 必须执行多次扫描。在 PostgreSQL 16 及更早版本中,vacuum 操作所能使用的 maintenance_work_mem 配额为 1GB。PostgreSQL 17 及更高版本使用 TidStore,它会动态分配内存,而不使用单一分配数组,从而使 vacuum 能够更高效地使用 maintenance_work_mem。

启用并行 vacuum

对于 vacuum 手动操作,您可以启用并行 vacuum,以便 PostgreSQL 为每个索引分配一个 vacuum worker 并进行并行处理。

要启用并行 vacuum,请根据数据库实例的可用 vCPU 数量和表上的索引数量调整 max_parallel_maintenance_workers 设置。

有关更多信息,请参阅 Amazon RDS for PostgreSQL 和 Amazon Aurora PostgreSQL 中的并行 vacuum。

监控数据库使用的事务数量

当 autovacuum 操作无法完成 vacuum 时,数据库可能会继续增加。您可以使用 Amazon CloudWatch 指标 MaximumUsedTransactionIDs 来获取数据库使用的最大事务数量。

此外,请为 MaximumUsedTransactionIDs 指标创建 CloudWatch 警报,以便在事务数量达到您指定的值时发送通知。有关更多信息,请参阅在 Amazon RDS for PostgreSQL 中实施事务 ID 回卷预警系统。

要在 Amazon RDS 控制台上监控 MaximumUsedTransactionIDs,请完成以下步骤:

  1. 打开 Amazon RDS 控制台。
  2. 在导航窗格中,选择 Databases(数据库),然后选择您的数据库。
  3. 在 Logs and Events(日志和事件)选项卡中,您可以在 Recent events(近期事件)部分中查看 MaximumUsedTransactionIDs。

如果您已达到 MaximumUsedTransactionIDs 配额,则必须对表执行 vacuum 操作。

要识别 vacuum 阻止程序,请参阅识别并解决 RDS for PostgreSQL 中的激进 vacuum 阻止程序。