背景
PostgreSQL 目前默认的存储引擎,事务可见性需要依赖行头的事务号,因为事务号是32位的,会循环使用。
在一条记录产生后,如果再次经历了20亿个事务,必须对其进行freeze,否则数据库会认为这条记录是未来事务产生的(可见性判断)。
因此FREEZE操作是数据库在32位事务号的情况下,经常要做的。
对全表进行FREEZE操作时,会扫描整表,将大于指定阈值least(autovacuum_freeze_min_age, 表级参数vacuum_freeze_min_age)年龄的记录设置为freeze。可能导致大量的读IO,写IO(主要是写数据文件,WAL日志, full page write WAL)。
一些参数决定数据库在什么时候触发FREEZE,以及触发FREEZE时,冻结哪些记录,以及是否涉及到调度(sleep)。
同时很多参数有库级、表级选项。表级优先,然后是库级,最后是实例级。
1、多久检查一次哪些表是否需要FREEZE
postgres=# show autovacuum_naptime ;
autovacuum_naptime
--------------------
1s
(1 row)
默认值是60s, 启动下一个autovacuum之前的等待时间:autovacuum_naptime= 60s(autovacuum_naptime/N)其中N是实例中数据库的总数,autovacuum_max_workers = 3 (Default)
2、哪些表需要被自动FREEZE,
超过如下阈值,如果设置了表级参数则以表级参数为准,否则以系统参数为准。
表级参数
autovacuum_freeze_max_age
autovacuum_freeze_table_age
系统级参数
autovacuum_freeze_max_age
autovacuum_freeze_max_age=200000000(default)
3、手工执行普通vacuum时,哪些表会被扫描全表,并freeze
超过如下阈值
系统级参数
vacuum_freeze_table_age
vacuum_freeze_table_age=150000000(default) 表的年龄大于此值时,会执行急切模式(扫描所有未全部冻结的页面,急切冻结的触发条件是pg_database.datfrozenxid<oldestxmin-vacuum_freeze_table_age;懒惰模式扫描所有存在死元祖的页面,即使某页有满足freeze的元祖但没有死元组的情况也不会扫描此页,冻结xmin小于freezelimit_txid的元组,freezelimit_txid的计算前面也提到过,freezelimit_txid=oldestxmin-vacuum_freeze_min_age)
注意,现在PG支持VM文件里面记录一个PAGE是否需要被FREEZE,所以即使全表扫描,也会根据VM标记位,跳过一些BLOCK,所以FREEZE并不一定会产生大量读IO。根据表的情况而定。
3、触发FREEZE时,哪些记录需要被FREEZE
超过如下阈值的记录被FREEZE,如果设置了表级参数则以表级参数为准,否则以系统参数为准。
表级参数
autovacuum_freeze_min_age
系统级参数
vacuum_freeze_min_age
vacuum_freeze_min_age= 50000000(default)
4、FREEZE后台进程的调度(sleep)。
current_setting('autovacuum_vacuum_cost_delay') as v7, -- 自动垃圾回收时, 每轮回收周期后的一个休息时间, 主要防止垃圾回收太耗资源. -1 表示沿用vacuum_cost_delay的设置
current_setting('autovacuum_vacuum_cost_limit') as v8, -- 自动垃圾回收时, 每轮回收周期设多大限制, 限制由vacuum_cost_page_hit,vacuum_cost_page_missvacuum_cost_page_dirty参数以及周期内的操作决定. -1 表示沿用vacuum_cost_limit的设置
current_setting('vacuum_cost_delay') as v9, -- 手动垃圾回收时, 每轮回收周期后的一个休息时间, 主要防止垃圾回收太耗资源.
current_setting('vacuum_cost_limit') as v10, -- 手动垃圾回收时, 每轮回收周期设多大限制, 限制由vacuum_cost_page_hit,vacuum_cost_page_missvacuum_cost_page_dirty参数以及周期内的操作决定.
current_setting('autovacuum') as autovacuum -- 是否开启自动垃圾回收
以下是用于调整autovacuum相关的IO参数:
• autovacuum_vacuum_cost_limit : autovacuum可达到的总成本限制(结合所有autovacuum作业)
• autovacuum_vacuum_cost_delay : 当一个清理工作达到autovacuum_vacuum_cost_limit指定的成本限制时,autovacuum将休眠数毫秒
• vacuum_cost_page_hit : 读取已在共享缓冲区中且不需要磁盘读取的页的成本.
• vacuum_cost_page_miss : 获取不在共享缓冲区中的页的成本.
• vacuum_cost_page_dirty : 在每一页中发现死元组时写入该页的成本.
谨慎设置autovacuum_max_workers:
• 通常,此成本平均分配给实例中运行的所有autovacuum过程的autovacuum_max_workers数。
• 因此,增加autovacuum_max_workers可能会延迟当前运行的autovacuum workers的autovacuum执行(workers增大平均分配给autovacumm的cost就少 时间就会延长)
• 而增加autovacuum_vacuum_cost_limit可能会导致IO瓶颈。
• 可以通过设置单个表的存储参数来重写此行为,这样会忽略全局设置。
参考:
https://github.com/digoal/blog/blob/master/201804/20180411_01.md