VACUUM调优和自定义预定vacuum作业

发布时间 2023-11-25 19:45:17作者: jl1771

PostgreSQL 的内置 autovacuum 功能正在不断改进,一个又一个版本。它变得越来越强大,同时减少了开销并解决了边缘情况。我认为没有任何 PostgreSQL 版本是在没有任何 autovacuum 改进的情况下推出的,毫无疑问,它对于大多数用例来说已经足够好了。

但是,这仍然远非适合任何特定环境的完美选择。在处理许多客户环境时,我们不断看到内置逻辑不够用的情况。

常见问题/限制

  1. 在高峰时段,表成为 autovacuum 的候选对象
    autovacuum 设置基于scale factors/thresholds。当表上有大量事务时,超过表这些限制的可能性很高——这是高峰时段。实际上,它在非常错误的时间启动的。

  2. 急需vacuum的表
    经常看到一些表成为 vacuuming 的候选对象并反复占用所有 worker 的情况是很常见的。而候选名单中的其他表很长一段时间都没有被vacuum。当前的 autovacuum 情报不足以了解谁更需要清理并给予更好的优先级。

  3. 无法动态控制 autovacuum workers 的油门
    这可能是最糟糕的。即使有一个知情的 DBA,他想要autovacuum_vacuum_cost_limit根据需要或时间窗口调整并向 PostgreSQL 发出信号。
    例如:

    ALTER SYSTEM set autovacuum_vacuum_cost_limit = 2000;
    select pg_reload_conf();
    

    这对当前运行的autovacuum worker没有影响。只有下一个worker启动时才会考虑这个设置。所以这不能用来解决问题。

  4. DBA 调整参数的尝试常常适得其反
    在看到陈旧的表和饥饿的表后,绝望的 DBA 保持积极的设置和更多的worker。很多时候,这会使系统超出其极限,因为当系统已经有大量活动会话时,一切都会在错误的时间发生。乘以maintenance_work_mem工人的分配。系统性能受到很大程度的影响。我见过的最糟糕的情况是 autovacuum workers 占用了高达 50% 的服务器资源。

  5. 活动时间窗口期间的 autovacuum 违背了它自己的目的
    如果在高活动窗口期间需要时间才能完成,autovacuum worker 将引用旧的 xid/快照。因此,它不会清除在同一持续时间内生成的死元组,这与 autovacuum 的目的背道而驰。

  6. 饥饿的表会触发环绕式预防 autovacuum
    很常见的是,需要较长时间自动清理范围autovacuum_freeze_max_age和 预防回卷主动清理的表会被触发。

由于这种低效性,我们不断看到 DBA 倾向于完全禁用 autovacuum,并引发更多问题甚至中断。至少,我对 PostgreSQL 新手的请求是,请永远不要尝试关闭 autovacuum。这不是解决与 autovacuum 相关的问题的方法。

调整 autovacuum

调整 autovacuum 显然是第一步。

全局级别设置

参数autovacuum_vacuum_cost_limitautovacuum_vacuum_cost_delay是控制 autovacuum worker 油门的主要两个参数。autovacuum_max_workers控制有多少worker将同时在不同的表上工作。默认情况下,autovacuum_vacuum_cost_limit将被禁用 (-1),这意味着其他参数的值vacuum_cost_limit将生效。因此,建议的第一件事是设置一个值,autovacuum_vacuum_cost_limit该值将帮助我们单独控制 autovacuum workers。

我在许多安装中看到的一个常见错误是将其autovacuum_max_workers设置为非常高的值,如 15!。假设这会使 autovacuum 运行得更快。请记住,这autovacuum_vacuum_cost_limit是在所有worker之间分配的。因此,worker数量越多,每个worker的运行速度就越慢。如上所述,较慢的worker意味着无效的清理。而且,它们每一个最多可以占用maintenance_work_mem。一般情况下,默认值autovacuum_max_workers3个就足够了。请考虑仅在绝对必要时才增加它。

表级分析设置

实例级别的全面调优设置可能对一些表不起作用。这些异常值需要特殊处理,并且在表级别调整设置可能变得不可避免。我将从那些经常成为 autovacuum 候选者的表开始。

PostgreSQL 日志参数log_autovacuum_min_duration提供了那些经常成为候选者的表以及那些花费大量时间和精力的 autovacuum 运行的详细信息。就个人而言,我更喜欢以此为起点。通过比较 pg_stat_all_tables 在两个不同时间戳下的 autovacuum_count,可以获得 atuovacuum 运行的摘要。我们需要考虑的是 HOT (Heap Only Tuple) UPDATE和fillfactor. 可以使用同一个视图(pg_stat_all_tables)的n_tup_hot_upd来分析 HOT UPDATE信息。,调整它可以大大降低 vacuum 需求。

配备所有这些信息分析,可以调整特定的表级设置。例如:

alter table t1 set (autovacuum_vacuum_scale_factor=0.0, autovacuum_vacuum_threshold=130000, autovacuum_analyze_scale_factor=0.0, autovacuum_analyze_threshold=630000, autovacuum_enabled=true, fillfactor=82);

补充计划vacuum作业

我们的目标不是禁用 autovacuum,而是用我们对系统的了解来补充 autovacuum。它根本不复杂。我们能做的最简单的方法是在表或其 TOAST 具有最大年龄的表上运行“VACUUM FREEZE”。

例如,我们可以有vaccumjob.sql以下内容的文件

WITH cur_vaccs AS (SELECT split_part(split_part(substring(query from '.*\..*'),'.',2),' ',1) as tab FROM pg_stat_activity WHERE query like 'autovacuum%')
select 'VACUUM FREEZE "'|| n.nspname ||'"."'|| c.relname ||'";'
  from pg_class c 
  inner join pg_namespace n on c.relnamespace = n.oid
  left join pg_class t on c.reltoastrelid = t.oid and t.relkind = 't'
where c.relkind in ('r','m') 
AND NOT EXISTS (SELECT * FROM cur_vaccs WHERE tab = c.relname)
order by GREATEST(age(c.relfrozenxid),age(t.relfrozenxid)) DESC
limit 100;
\gexec

该查询获取 100 个当前未进行 autovacuum 的旧表,并对它们运行“VACUUM FREEZE”。(末尾的 \gexec 执行查询输出)

这可以使用corn来调度低活动窗口,如下所示:

20 11 * * * /full/path/to/psql -X -f /path/to/vacuumjob.sql > /tmp/vacuumjob.out 2>&1

如果有多个低影响的窗口,那么可以使用多个时间表来利用它们。

实际上,我们已经看到,基于 table age 方法的补充的、预定的 vacuum 作业具有以下积极作用

  1. 这些表在高峰时段再次成为候选者的机会大大降低。
  2. 能够在 vacuum 和 freeze 操作的非高峰时段非常有效地利用服务器资源。
  3. 由于候选者是根据与默认标准(scale factor和threshold)完全不同的标准(表年龄)选择的,因此消除了一些表永远挨饿的可能性。此外,这消除了同一张表一次又一次成为 vacuum 候选者的可能性。
  4. 在客户/用户环境中,预防 autovacuum 回卷几乎再也不会被报告。

概括

autovacuum没有调优,或者设置很差,从实例级一直用到表级,这种情况并不少见。总结一下:

  1. 默认设置在大多数系统中可能效果不佳。 在几个表上重复运行 autovacuum 而其他表缺乏 autovacuum 是很常见的。
  2. 糟糕的设置可能会导致 autovacuum worker 占用相当一部分服务器资源而收效甚微。
  3. 当系统进行大量事务时,autovacuum 自然会在错误的时间启动。
  4. 实际上,对于那些处理繁重事务和具有大量事务的表,并且预计会有峰值和负载高峰时间段的系统来说,计划的 vacuum 作业变得很有必要。

清晰的分析和调整是很重要的。我们总是强烈建议你做一个自定义的 vacuum 工作,它占用你的知识对系统和时间窗口的影响最小。