开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共1300人左右 1 + 2 + 3 + 4) 3群即将突破 400 会关闭自由申请,新人会进4群,另欢迎 OpenGauss 的技术人员加入。
PostgreSQL 16 中改进了vaccum freezing的性能提升,具体在哪里有相关性能的提升,这里进行一个详述。
在2022年8月25日,Peter Geoghegan 给PG Hacker的邮件中指出,对于之前的PG的版本需要进行Patch,相关的工作在PostgreSQL 15中提出,这里主要的问题起源于 vacuum_freeze_min_age 这个参数,这里的理念是来源于PG8.3后对于冻结元组是更倾向于积极的层面,或是延迟方式处理的选择性的问题。
#idle_session_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_table_age = 150000000
#vacuum_freeze_min_age = 50000000
#vacuum_failsafe_age = 1600000000
#vacuum_multixact_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
在这个问题上,之前的方案都是趋向于尽力延迟的行为,目的是提高日常postgresql在运行中的遇到vacuum,autovacuum后操作的性能问题。在我们对于表中的 tuple 进行处理的情况下,是需要对于表中的元组的t_informask 进行标记的。
举例我们针对上面的配置中的 vacuum_freeze_min_age 参数设置为5千万,也就是当我的目前使用的到的xmin 为 50006000 时Postgresql 会启动, 50006000 - 50000000 = 6000 ,则xmin小于 6000的元组都会被冻结。
但是在我们运行 vacuum 普通模式中,vacuum是通过 vm文件,也就是我们的 visibility map 来进行的那些数据页面需要进行扫描,这里主要指的是数据的脏页。但这就导致一个问题,如果这个页面的从来没有被修改过,也就不存在脏页,不存在脏页的情况下普通的 vacuum 是无法扫描到这些页面的,也就无法进行冻结的工作。
如果发生这样的问题的情况下,如这个页面就是一个log 表,根本就不会有update的情况下,这个表页面是无法被扫描,也就无法进行xid 的冻结工作,而无法进行冻结的工作,最终会导致 aggressive vacuum 的工作,而如果发生这个 aggressive vaccum 的工作则和普通的vacuum的工作不一样,他不管vm文件中的记录,在尽显vacuum的时候会对这个表进行全部页面的扫描。
为避免这个问题的发生,在PG15中引入了优化参数autovacuum_insert_threshold 和 autovacuum_vacuum_insert_scale_factor
#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts
# before vacuum; -1 disables insert
# vacuums
#autovacuum_analyze_threshold = 50 # min number of row updates before
# analyze
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of inserts over table
# size before insert vacuum
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
通过这样两个参数来弥补上面提到,类似日志表的问题,导致可能引起的aggressive vacuum, 而对于 aggressive vacuum 的操作也是针对表的,则vaccum_freeze_table_age 就是判断如何对表进行 aggresive vacuum 的参数之一,通过当前最老的 xmin - pg_class.relforzenxid(表)> vacuum_freeze_table_age的情况下就会触发
#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
#idle_session_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_table_age = 150000000
#vacuum_freeze_min_age = 50000000
#vacuum_failsafe_age = 1600000000
#vacuum_multixact_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
当然如果一个表,产生了需要进行 vacuum freezing的工作,如果在业务繁忙的情况下,系统还是能承受的,但是如果当多个表都在比较近的情况下,都触发了 vaccum freezing的工作,那么如果是大表很长一段时间autovacuum 可能都无法完成一个表的清理工作,这将引起连锁反应。
说到这里,我们还没有说到今天的主题,只是对要讲的问题的前期知识进行了一个铺垫。然后就有了三封邮件
1 set relfrozenxid to oldest extant xid seen by vacuum
2 generalize how vacuum skips all-frozen pages
3 simplify lazy_scan_heap's handing of scanned pages
这三封邮件均来自于 Peter Geoghegan
这三封邮件均围绕这个缺陷的问题,来进行讨论和方案的建议
第一份邮件中,主要表达在非aggresive vacuum 中对于表中relfrozenxid的无法有效提升的吐槽,同时也提出在未来的PG程序设计中,需要在普通的vacuum也能推进更有效进行 freezing 工作的建议。
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=44fa8488
第二封邮件 中比较了non-aggressive vacuum 和 aggressive vacuum之间的不同,并提出对比二者在处理跳过冻结页面的工作方式上的不同,在邮件里面表达了对于non-aggressive vacuum在处理工作方式的安全性的考虑的满意,同时也对 aggressive vacuum在处理此类问题的缺陷。
The aggressive case
reasoned that the page (a skippable page) must have at least been
all-frozen in the recent past, so skipping it won't make relfrozenxid
advancement unsafe (which is never okay for aggressive VACUUMs).
并且这里邮件给出了一件,将改变如何进行页面跳过的评判方式,与有关的计数器的重新设计的问题。新的方式将对于要跳过的页面使用标志位的方式,使用范围圈定的方式,而不是对于独立页面的标志形式。
Consistently avoid the issue by generalizing how we skip frozen pages
during aggressive VACUUMs: take the same approach when skipping any
skippable page range during aggressive and non-aggressive VACUUMs alike.
The new approach makes ranges (not individual pages) the fundamental
unit of skipping using the visibility map. frozenskipped_pages is
replaced with a boolean flag that represents whether some skippable
range with one or more all-visible pages was actually skipped.
这里邮件给出的建议是,如何进行安全的frozen,仅仅需要对于没有frozen 的页面,同时比当前最老的 xmin 之后的页面进行扫描就可以了。
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=f3c15cbe
第三封邮件中对于 vacuum如何设置relfrozenxid 进行了一个描述,与设置值的规则的问题并针对这个值在表上进行更新的这些值应该被写入到表中 new relfrozenxid 和 new relminmxid 中作为每次vacuum的工作中最后的步骤。而这个值来自于以下的可能性
1 来自于表中 tuple 元组的 xmin , xmax 或者 xvac 等部分
2 可能来与与某个表的 Multixacts
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0b018fab
当然这些信息,在PostgreSQL 16上得到了验证,参见下方截图,this makes full table freeze vacuums less necessary.
PostgreSQL 16 release note 截图
PostgreSQL 15 部分版本release not 截图
相关信息的提交人和代码修改者