问题背景
线上 RDS for PostgreSQL 实例发现短时间内,从指标中查看到有如下信息:
- 可用存储空间迅速降低
- 此时实例并没有大量的 DML,而 WAL 日志却增长异常
- CPU,内存,磁盘 IO / 带宽等指标均有突增
问题分析
查看 PostgreSQL 错误日志,查看到有如下信息:
automatic aggressive vacuum to prevent wraparound of table
可以看到这段时间内发生了 aggressive vacuum
什么是 vacuum
在 PostgreSQL 中,autovacuum 的作用主要有如下四个方面:
- 清理 dead tuple,对页面进行重组
- 更新统计信息,保证执行计划的准确性
- 更新 VM,加速 index-only scans
- 避免 XID 回卷造成的数据丢失
触发 autovacuum 有如下两个条件:
- 表的年龄是否达到 autovacuum_freeze_max_age 配置值,如果达到,必须进行 aggresive vacuum
- 当表更新或者删除的元组数超过 autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor x table_size
同时我们需要注意的是,决定是否进行普通 Vacuum 和 aggressive vacuum 取决于如下两个参数:
- 通过 vacuum_freeze_min_age 来决定表中那些元组需要被 vacuum
- 通过 vacuum_freeze_table_age 来决定是否需要进行全表扫描,而不是通过 vm map 跳跃式扫描进行 vacuum,这种方式也被称为 aggressive vacuum
小结
PostgreSQL 中的 vacuum 可能导致大量的读写 IO,涉及到数据文件,WAL 日志文件的读写,还会伴随着 CPU,内存等指标飙升,而 aggressive vacuum 对于整个数据库的性能和稳定性的影响尤其明显。
一些建议
- 建议监控 database,表的年龄。监控的目的在于提前发现,使用户可以选择合适的时间来手动执行 vacuum freeze,避免集中达到 aggressive vacuum 阈值引发 freeze 风暴。
- 避免大表,对于大表应使用分区表,并对大表设置不同的 vacuum 年龄
- 避免大事务,长事务,Long 2PC
如果您有其他的优化建议,欢迎留言,分享。
参考文档