前言
autovacuum在生产环境中必不可少,因为大量的统计信息依赖于它的处理。有的PGer可能信心满满,把这个全局开关给关了,然后自己去调试vacuum, 定期对一些表进行空间回收处理,这可有点危险了。已经有相当多的案例因为这个,导致系统最后变得莫名其妙,总的空间也不是你想象的那个方向去发展。
同时因为autovacuum有时候并不能有效的回收空间,在生产环境中实在是太常见了。一些相对高频的CURD的表,积累到一定时间以后,还一直往上涨。作为DBA的你,不感到心有不安吗?尤其是在Cloud环境下,不断增长的存储空间,意味着你这一方,或者是客户这一方,要为这新增的存储空间付费,意味着要多花钱。
在一般情况下,表所占用的空间确实存在一定程度的膨胀,这是因为PG独有的MVCC机制决定的,它vaccum截断的也只是尾部连续的空闲页。如果不连续,它也不会去回收那部分物理空间。另外,因为定期"dead"元组的清除或标记可能来不及,或者相应空间不连续,导致新插入的(包括更新操作导致的新插入),只能寻找或创建新的物理页(也叫块),从而导致空间继续往上涨。
这个时候,利用分区表的特性,我们可以定期或者可控的直接删除部分分区表,直接回收物理空间。
实例
我们曾经遇到过数次,目标表:ex_log,2000万条记录,直接不断涨到了148G。而按照我们自己的估算,一个相同规模的堆表,如果没有额外膨胀,最多也就10~15G的样子。同时,因为Cloud环境的限制,居然pg_repack等第三方插件也不能直接使用。而pg_repack的使用,本身对业务也还是有一定影响的,对存储空间也有额外要求。
利用ex_log本身的特性,它本身只需要保留7天以内的数据,7天到30天之间的,有一段后台程序,直接归档到S3。30天以前的归档彻底删除。那么,我们只需要每次在归档完之后,清除7天以前的数据就可以了。
在没有使用分区表之前,'DELETE'操作,结合autovacuum并不能有效的回收空间。使用分区表之后,每次只删除第8个分区的表(执行truncate即可)。而且这样操作以后,数据非常归整。哪一天的CUD都很有条理的落入到对应的分区当中。
改造过程:
要保证SLA的等级,即业务不能停,不能简单粗暴的更改表结构。
而是建一张新表ex_log_part, 以及对应的分区表。所有的新的INSERT操作都基于新表,DELETE,UPDATE操作,则兼顾旧表新表。Query操作操作的是旧表以及新表的UNION。即应用逻辑做适度调整,以适配新的变化。
在过了一个周期(至少7天以后),旧表当中应该没有数据了,就可以彻底truncate旧表,把旧表的空间完全回收。再返回改业务逻辑。
有点搞笑的是,在旧表记录条数为0的时候,我们发现它依然有近40个G的空间占用。这里就不贴图了。
在实际的生产环境当中,有不少这样的业务逻辑,分区表不仅是为了拆分表,有时候用它来辅助管理空间的回收,也是非常有用的。需要开发人员和运维双方有效配合。开发人员确保业务不中断,并不断迭代,最后删除原始表。运维人员在这期间可以监控系统状态,提供建议和帮助。
简单来说:不是不允许膨胀,而是要让膨胀保持在一个相对合理的范围以内。