ddia/pg/pg-tune-autovacuum.md
2018-02-08 14:07:06 +08:00

141 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Autovacuum Tuning Basics [译]
原文https://blog.2ndquadrant.com/autovacuum-tuning-basics/#PostgreSQL%20Performance%20Tuning
几个星期前我介绍了调优检查点的基础知识在那篇文章中我还提到了性能问题的第二个常见原因是autovacuum根据我们在邮件列表和我们的客户支持下看到的。所以让我跟随这个帖子关于自动调谐的基础知识。我将非常简要地解释必要的理论死元组膨胀和autovacuum如何处理它但是这篇博文的主要重点是调优 - 那里有什么配置选项,经验法则等等。
### 死元组
首先让我们简单地解释一下“死亡元组”和“膨胀”如果你想得到更详细的解释可以阅读Joe Nelson的文章详细讨论这个
当您在PostgreSQL中执行DELETE时又名元组不会立即从数据文件中删除。相反它只能通过在行首部中设置xmax字段来标记为已删除。对于UPDATE也可以看作PostgreSQL中的DELETE + INSERT。
这是PostgreSQL MVCC背后的基本思想之一因为它允许更大的并发性只需在不同的进程之间进行最小程度的锁定。这个MVCC实现的缺点当然是它留下了被删除的元组甚至在所有可能看到这些版本的事务完成之后。
如果不清理这些“死元组”对于任何事务实际上是不可见的将永远停留在数据文件中浪费磁盘空间而对于有许多DELETE和UPDATE的表死元组可能会占用绝大部分磁盘空间。当然这些死元组也会被索引引用进一步增加了浪费的磁盘空间。这就是我们在PostgreSQL中所谓的“膨胀”。当然查询必须处理的数据越多即使99的数据立即被“抛弃”查询就越慢。
### Vacuum和AutoVacuum
回收死元组占用的空间的最直接的方法是通过手动运行VACUUM命令。这个维护命令将扫描表并从表和索引中删除死元组 - 它通常不会将磁盘空间返回给操作系统,但会使其可用于新行。
注意:`VACUUM FULL`会回收空间并将其返回给操作系统,但是有一些缺点。首先它获得对表的**独占锁(Access Exclusive)**阻止所有操作包括SELECT。其次它本质上创建了表的副本使所需的磁盘空间增加了一倍所以当磁盘空间已经不足时不太实际。
`VACUUM`的麻烦在于它完全是手动操作 - 只有在您决定运行时才会发生而不是在需要时才会发生。你可以把它放到cron中每5分钟在所有的表上运行一次但是大部分运行的机会并不会真正清理任何东西唯一的影响是CPU和I / O在系统上的使用率会更高。或者你可能每天晚上只运行一次在这种情况下你可能会累积更多你想要的死元组。
这是我们使用**自动清理AutoVacuum**的主要目的;根据需要进行清理以控制浪费空间的数量。数据库确实知道随着时间的推移生成了多少个死元组每个事务都报告它删除和更新的元组的数量当表累积了一定数量的死元组时可以触发清理工作默认情况下是20我们将会看到。所以在繁忙的时候会更频繁地执行而当数据库大部分空闲的时候则更少。
### autoanalyze
清理死元组不是自动清理的唯一任务。它还负责更新优化程序在规划查询时使用的数据分布统计信息。您可以通过运行ANALYZE来手动收集这些数据但是会遇到与VACUUM类似的问题 - 您可能会经常运行或不经常运行。
解决方案也是类似的 - 数据库可以观察表中有多少行更改并自动运行ANALYZE。
注意ANALYZE的开销要大一点因为虽然VACUUM的成本与死元组的数量成正比开销很小当死元组数量很少时/没有ANALYZE必须在每次执行时从头开始重建统计数据。另一方面如果你不是经常运行它那么不好的计划选择的代价可能同样严重。
为了简洁起见,我会在后面的文章中大部分忽略这个自动清理任务 - 配置与清理非常相似,并且遵循大致相同的推理。
### 监控
在进行任何调整之前,您需要能够收集相关数据,否则您怎么能说您需要进行任何调整,或评估配置更改的影响?
换句话说,你应该有一些基本的监控,从数据库中收集指标。为了清理,你至少要看这些值:
* `pg_stat_all_tables.n_dead_tup` :每个表中的死元组数(用户表和系统目录)
* `(n_dead_tup / n_live_tup)` 每个表中死/活元组的比率
* `(pg_class.relpages / pg_class.reltuples)` 每行空格
如果您已经部署了监控系统(应该的),那么您很有可能已经收集了这些指标。总体目标是获得稳定的行为,这些指标没有突然或显着的变化。
还有一个方便的pgstattuple扩展允许您对表和索引执行分析包括计算可用空间量死元组等。
### 调整目标
在查看实际配置参数之前,让我们简要讨论一下高级调优目标,即更改参数时要实现的目标:
清理死元组 - 保持合理低的磁盘空间量,而不是浪费不合理的磁盘空间量,防止索引膨胀并保持查询速度。
最大限度地减少清理的影响 - 不要经常执行清理工作因为这会浪费资源CPUI / O和RAM并可能会严重影响性能。
也就是说,你需要找到适当的平衡 - 经常运行可能会不够经常运行。天平在很大程度上取决于您所管理的数据量您正在处理的工作负载类型DELETE / UPDATE数量
`postgresql.conf`中的大多数默认值是相当保守的原因有二。首先根据当时常见的资源CPURAM...默认值是几年前决定的。其次我们希望默认配置可以在任何地方工作包括树莓派Raspberry Pi或小型VPS服务器等小型机器。对于许多部署特别是较小的部署和/或处理大部分读取工作负载),默认的配置参数将工作得很好。
随着数据库大小和/或写入数量的增加,问题开始出现。典型的问题是清理不经常发生,当发生这种情况时会大大地干扰性能,因为它必须处理大量的垃圾。如果这些情况你应该遵循这个简单的规则:
* 如果它造成了损失,你不会经常这样做。
* 也就是说,调整参数,使得清理更频繁,每次处理更少量的死元组。
注意:人们有时遵循不同的规则 - 如果伤害了,不要这样做。 - 完全禁用自动清理。除非你真的(真的)知道你在做什么,并且有定期的清理脚本,否则请不要这样做。否则,你正在画一个角落,而不是性能有些下降,你将不得不面对严重退化的表现,甚至可能是停机。
所以,现在我们知道我们想要通过调谐实现什么,让我们看看配置参数...
### 阈值和比例因子
当然,你可能会调整的第一件事情是当清理被触发,这是受两个参数的影响:
autovacuum_vacuum_threshold = 50
autovacuum_vacuum_scale_factor = 0.2
并且每当无用元组的数目你可以看到pg_stat_all_tables.n_dead_tup超过
阈值+ pg_class.reltuples * scale_factor
该表将被视为需要清理。该公式基本上说高达20的表可能是清理前的死元组50行的阈值是为了防止对小表进行非常频繁的清理
默认比例因子适用于中小型的表格,但对于非常大型的表格来说效果并不理想 - 在10GB的表格上这大概是2GB的死元组而在1TB的表格上则是200GB。
这是一个积累了大量死元组的例子,并且一次处理所有的元组,这将会受到伤害。根据之前提到的规则,解决方案是通过显着降低比例因子来更频繁地执行此操作,甚至可能是这样:
autovacuum_vacuum_scale_factor = 0.01
这将限制仅减少到表格的1。另一种解决方法是完全放弃比例因子仅使用阈值
autovacuum_vacuum_scale_factor = 0
autovacuum_vacuum_threshold = 10000
这应该在产生10000个死元组之后触发清理。
一个麻烦的问题是postgresql.conf中的这些变化会影响到所有表实际上是整个集群并且可能会对小型表包括系统目录的清理产生不利影响。
当小桌子被更频繁地清理时,最简单的解决办法就是完全忽略这个问题。小桌子的清理将是相当便宜的,并改善工人数量
还没有提到的一个配置选项是autovacuum_max_workers那是什么意思那么清理不会发生在一个自动清理过程中但是数据库可以启动到实际清理不同数据库/表的autovacuum_max_workers进程。
这很有用,因为例如你不想停止清理小表,直到完成一个大表的清理(这可能需要相当多的时间,因为节流)。
麻烦的是用户假定工作人员的数量与可能发生的清理量成正比。如果将自动清扫工人的数量增加到6人那么与默认的3人相比工作量肯定会增加一倍对吧
那么不。几段前面描述的成本上限是全球性的所有的汽车真空工人都是共同的。每个工作进程只获得总成本限制的1 / autovacuum_max_workers所以增加工作者数量只会使他们变慢。
这有点像高速公路 - 车辆数量增加一倍,但速度减半,只能让你每小时到达目的地的人数相同。
所以如果你的数据库的清理跟不上用户的活动,那么增加工作者的数量并不是一个解决方案,除非你也调整了其他的参数。
### 按表限流
实际上当我说成本限制是全局的所有的自动清理Worker共同分担的时候我一直在说谎。与缩放因子和阈值类似可以设置每个表的成本限制和延迟
```sql
ALTER TABLE t SET (autovacuum_vacuum_cost_limit = 1000);
ALTER TABLE t SET (autovacuum_vacuum_cost_delay = 10);
```
全球成本计算中不包括处理这些表的工人,而是独立地进行限制。
这给了你相当多的灵活性和权力,但不要忘记 - 拥有巨大的权力是很大的责任!
在实践中,我们几乎从不使用这个功能,有两个基本的原因。首先,您通常希望在后台清理上使用单个全局限制。其次,多个工人有时被扼杀在一起,有时独立地使监督和分析系统的行为变得更加困难。
### 概要
所以这就是你调整自动清理的方法。如果我必须把它归纳成几条基本规则,那就是这五条:
* 说真的不要禁用autovacuum除非你真的知道你在做什么。
* 在繁忙的数据库上(做大量更新和删除),特别是大数据库,你可能应该减小比例因子,这样更频繁地进行清理。
* 在合理的硬件(良好的存储,多核心)上,你应该增加节流参数,以便清理能够跟上。
* 单独增加autovacuum_max_workers在大多数情况下并不会真的有帮助。你会得到更多的进程变慢。
* 你可以使用ALTER TABLE来设置每个表的参数但是如果你真的需要的话可以考虑一下。这使得系统更复杂更难以检查。
我原本包括几个部分解释什么时候autovacuum没有真正的工作以及如何检测它们以及什么是最好的解决方案但博客文章已经太长了所以我会在几天后分开发布。