孤独750 发表于 2016-12-21 10:33:31

PostgreSQL Cost Based Vacuum探秘

  PostgreSQL cost based vacuum的意思就是指每次 vacuum,进行heap scan时,都会基于IO cost进行sleep。如果IO cost越大,总体sleep的时间就会越长。也就是说scan 表,并且清理dead tuple
  是断断续续的,并不会一次性全vacuum完。这样子做的原因就是尽量避免对当前DML操作的影响,从而减少因vacuum而对系统IO的压力。

  cost based 有几个非常重要的参数:

[*]vacuum_cost_delay : 默认vacuum_cost_delay为20毫秒。 heap scan时,需要sleep的时间。
[*]vacuum_cost_page_hit :vacuum时,page在buffer中命中时,所花的代价。默认值为1。
[*]vacuum_cost_page_miss:vacuum时,page不在buffer中,需要从磁盘中读入时的代价默认为10。
[*]vacuum_cost_page_dirty:当vacuum时,修改了clean的page。这说明需要额外的IO去刷脏块到磁盘。默认值为20。
[*]vacuum_cost_limit:默认为200,单位时间内多个vacuum worker完成vacuum而不被sleep 惩罚的所允许IO最大消耗值。
  上面带有字样“page”的参数是在readbuffer时,计算的代价。它会及时更新到vacuumCostBalance值中,这个值是每个值的总和。
  即:vacuumCostBalance=vacuum_cost_page_hit * x + vacuum_cost_page_miss*Y+ vacuum_cost_page_dirty*Z。其中x,y,z为访问次数。按默认值转换后为:vacuumCostBalance=1* x + 10*Y+ 20*Z。
  vacuum_cost_limit有两个用途:
  其一是用来计算每个vacuum worker毫秒级别所允许消耗的最大IO,vacuum_cost_limit/vacuum_cost_dely。也就是说每个worker会平摊掉这个cost值。一句话概括就是所有vacuum worker在vacuum_cost_delay时间段
  内所允许消耗的最大IO。当新的vacuum_worker进来进,都会rebalance一把,得到此worker的VacuumCostLimit值。
  其二是在cost base模式下,用来控制每次delay的时间。每次delay最小值为vacuum_cost_delay值,最大值为4*vacuum_cost_delay值。判断依据为VacuumCostBalance / VacuumCostLimit的值是否
  大于”4“。大于”4“之后就是4*vacuum_cost_delay。PG设置delay最大值为4倍,就是不希望延迟太长。其实4倍的效果已经是非常明显了。因为在vacuum过程中需要scan heap,index等,而且delay都是
  在block级别的。因此,如果某个表IO很高时,就需要通过调高vacuum_cost_limit值来缩短delay时间,从而减少空间爆增量。
  从上面两点看出,这是一个非常重要的值,如果这个值设置不够高,也就是说跟当前的系统TPS不匹配的话,那么导致的结果就是vacuum老是被delay,一个TPS高的表,往往就需要很常的时间来vacuum了。
  因此,如果高TPS系统,本人还是建议设置的高些。不然高TPS表,不被及时vacuum完成,而是被delay住,那么将导致这个表的增长是非常恐怖的,往往会引起性能问题。这个时候变成大表之后,一般vacuum已经不
  起作用了,需要vacuum full来处理,而vacuum full是会锁表的。这会导致对应用严重伤害。这个时候有人会跳出来说,vacuum频率高点可能会影响当前的性能。这个当然会有,在IO上会有争用。但是这个性能问题,我们
  是可能通过其它方式来规避的。比如说应用设计以及数据库分片技术等。
  我们先看一个例子,来分析PG是如何基于IO cost,从而来delay vacuum 的:

  从上面,看Deal Tuples为6116,已经超过threshod值1651,所以后面开始vacuuming “public.sbtest1”。

  但是总共花了45.64s,才vacuum完成。这个时候的cost_limit值为100。

  我调整了cost_limit的值到1000,这个时候,可以看到只用了5.85秒。vacuum速度快多了。
  这是为什么呢?原因就是每次scan tuple时,delay的时间少了。PG在索引,表,visibility map等scan进,都嵌入了vacuum_delay_point()方法。
  这使得delay的效果是堆积的。当我改成400后,12.84s。

  从上面的例子中,已经完全说明了,为什么有些高TPS系统,vacuum老是起不了效果。高DML操作表,一直被增大的原因。
  另外,autovacuum已经能做到表级并行了。下面三个表位于同一个库中。
页: [1]
查看完整版本: PostgreSQL Cost Based Vacuum探秘