PostgreSQL vacuum 内核源码机理

 

    为了能全面理解PG整个vacuum的过程,专门绘制了下面一个完整的过程图,用以记录其内核源码实现机理。整个过程比较复杂。大致分为以下几个部分:

一、pg_ctl

    这个负责PG server起动,调用start_postmaster后,起动PG主server进程postmaster。后面任务交给postmaster来处理。

二、postmaster

    负责起动autovacuum launcher,起动autovacuum launcher后台进程后,控制权交给launcher。

三、autovacuum launcher和 autovacuum worker

     这两个进程的源码都在autovacuum.c中,autovacuum.c中的源码可以大致上为分两个阶段:

     第一个阶段:主要为launcher的职责。负责为将要起来工作的worker分配AutoVacuumShemStruct结构槽,并且选择一个最近最少vacuum或者最需要冻结xid的DB。

         然后将此dbid赋值给worker,并发送信号给postmaster,说已经准备好woker了,可以起动了。

     第二个阶段:主要为worker的职责。postmaster接收到launcher的信号后,起动AutoVacuumShemStruct中状态为startingwork的auto vacuum worker。

        主要是工作是fork一个进程,并将pid赋值给此worker,然后发信号给launcher,说你可以准备起下一个worker了。

 

进入autovacuum worker后:

1.首先收集需要vacuum或者analyze的表。需要vacumm的表的判断依据是Dead Tuples的值超过:vacuum_threshold + vacuum_scale_factor * num_tuples。

需要analyze的表的判断依据是DML的记录超过此值:analyze_threshold + analyze_scale_factor*num_tuples。

 

2.找到第一个需要vacuum的表,并将此表的 vacuum option参数赋值给autovacuum worker,即MyWorkInfo结构体(指向AutoVacuumShemStruct中的worker)。

如cost_limit,cost_delay,cost_limit_base参数。其中cost_limit_base的值等于cost_limit的值。

 

3.调整每个在running 的worker的cost_limit值。worker中有cost_limit和cost_limit_base两个变量。cost_limit和cost_limit_base的值,在刚开始没有经过balance时,是相等的。

但是经过balance过,cost_limit的值会发生变化。而cost_limit_base的值基本上就是表级别用”alter table xxx set(autovacuum_vacuum_cost_limt=1000)”命令来设置的值。

设置好后,在balance过程中,cost_limit_base的值基本上不变。因此才在名字上加了”base”用于区别。如果没有设置,cost_limit和cost_limit_base都是autovacuum_vacuum_cost_limit这个在postgresql.conf配置的值。
表级别的设置值优先级高于postgresql.conf中定义的全局值。balance时,参考cost_limit_base的值对每个running worker 的cost_limit进行调整。cost_limit最大值

不超过cost_limit_base,即需在[1,cost_limit_base]闭区间内。cost_limit值的意义其实就是每个毫秒时间内vacuum所能允许消耗的IO cost值。即:cost_limit/cost_delay。

而这个cost_limit/cost_delay又会被autovacuum_max_workers个workers平分掉,而不是简单的做个限制。如果超过,就是最高以4倍的cost_delay来惩罚,这将导致vacuum过程严重变长。

详细说明见”第6“步。

 

4.balance完成后,接着就用上面的cost_limit和cost_delay值去更新VacuumCostDelay和VacuumCostLimit这两个值。并将VacuumCostBalance的值置为“0”。这三个值的意义在”第6“步中讲。

 

5.接着去判断此次发起的是哪种类型的vacuum: vacuum full 还是lazy vacuum。如果是vacuum full,相当于重建relation,需要AccessExclusiveLock。如果是lazy vacuum,

则是SharedUpdateExclusiveLock。lazy vacuum 还要判断是否需要full scan。如果是full scan,需要更新pg_class中的relfrozenxid值。partial scan只清理dead tuple和compact free space。
请见另外一篇文章“PostgreSQL vacuum原理—vacuum揭秘”。

 

6.最后就是去scan heap了。按每个block依次遍历。每遍历一个block都需要 delay一次。在这里上面“第4步”中的三个值就派上用场了。每次sleep的时间按公式:

msec=VacuumCostDelay*VacuumCostBalance/VacuumCostLimit

如果上面这个值大于4倍的VacuumCostDelay值,那么msec就等于“4*VacuumCostDelay”。否则就按上面公式算出的值进行sleep。sleep完成后,将MyWorkInfo中的cost_limit和cost_delay

赋值给VacuumCostDelay,VacuumCostLimit,以适应balance过程。然后再次将VacuumCostBalance设置为“0”。

其中VacuumCostDelay和VacuumCostLimit基本上每次balance后就不变了。唯有VacuumCostBalance值是在整个block遍历的过程中变化的,它的cost计算是根据当前page hit,page miss

以及page dirty来计算的,请见另外一篇文章“PostgreSQL Cost Based Vacuum探秘”。因此如果一个表的update,delete操作很高,那么dead tuple就非常多,导致vacumm时,

VacuumCostBalance值变高。因此如果要加快vacuum,减少一个表在vacuum时的delay时间,只有把cost_limit的值提高,也就是postgresql.conf中autovacuum_vacuum_cost中的值调大,

才会使上面公式的值就小。

 

上面还是太理论了,还是有点难懂的。我举个简单的例子来说明下cost的计算:

假设当前有3个表需要vacuum,而且起了3个worker。每个表的autovacuum_vacuum_cost_limit都为默认值200,autovacuum_vacuum_cost_delay的值都为10ms。另外postgresql.conf中

配置的这两个值也是默认值,分别为200和10ms。那么cost_limit 的值就是:200/3=66。当然,如果在每个表的cost_limit_base都不同的情况下,计算会复杂点。总体思路就是cost_limit_base

大的表,分到的cost_limit值也大些。但是区间还是在”第3步”中的区间,即[1,cost_limit_base]。cost_limit的可配置范围在[1,10000];cost_delay的值在[1,100],单位是ms。

计算公式我归纳如下:

cost_total=sum(cost_limit_base/cost_limit_delay),每个runing worker都加起来。

cost_avail=autovacuum_vacuum_cost_limit/autovacuum_vacuum_cost_delay,postgresql.conf中配置的值。

每个worker的cost_limit=max(min(cost_avail*cost_limit_base/cost_total,cost_limit_base),1)。所以上面的值代入,得到约为66。

 

PG用这种算法,完善实现了cost based vacuum。详细图见下:

vacuum

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30088583/viewspace-1618496/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30088583/viewspace-1618496/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值