digoal
2021-08-31
PostgreSQL , 膨胀 , 收缩 , vacuum full , pg_repack
十个中年人九个肥胖, 数据库用久了也会膨胀. 原因是什么?
1、产品的问题点
- 当表膨胀后普通的vacuum 操作无法回收已经占用的磁盘空间, (仅末尾空块可从磁盘回收).
- 使用pg_repack(增量复制+数据文件filemap切换, 短暂锁表)或vacuum full(要锁全表, 影响业务)回收磁盘占用的空间都需要额外的磁盘来临时存储重组后的数据.
2、问题点背后涉及的技术原理
- PG 的dead tuple和有效的tuple都存储在原来的datablock中, 通过vacuum清理, 清理只是把空间释放允许写入, 而不是从磁盘上清理掉. 未及时清理就会膨胀, 即使清理了, 如果未来新的数据没有写进来填空, 也是处于膨胀状态.
- 索引也会膨胀. 有索引的表, 随着数据的写入, 索引page可能会产生分裂, 导致一些索引页没有被充分的利用.
- 普通的vacuum只能truncate数据文件末尾的空block, 所以我们可以将末尾的tuple移动到前面, 从而从磁盘回收末尾的block.
- 为什么只能truncate数据文件末尾的空block?
- 因为非末尾的block被清掉之后, 这个存储在被清理的block之后的block里面的记录的寻址会发生变化, 例如第二个数据块回收掉, 那么2号数据块后面的数据块的编号都需要减1, 而索引的ctid指向的是原来的编号, 因此会导致索引内容错误. 当然, 我们可以在meta信息里增加1个bitmap文件存储真空块(已回收的中间blockid, 寻址时通过这个数据再进行block定位), 但是会增加寻址的复杂度, 性能可能下降. 而且PG使用的是文件系统管理, 可能还需要文件系统支持这样的"空间压缩技术".
3、这个问题将影响哪些行业以及业务场景
- 频繁更新的业务
- 《DB吐槽大会,第1期 - PG MVCC真头疼》
4、会导致什么问题?
- 如果你的环境已经拮据到无法提供额外的磁盘空间来存放整理后的数据, 那么将无法实施回收操作.
5、业务上应该如何避免这个坑
- 我之前写过一篇这样的文章, 《PostgreSQL 通过行迁移 无需额外空间 回收垃圾膨胀磁盘空间》
6、业务上避免这个坑牺牲了什么, 会引入什么新的问题
- 以上方法的维护成本较高, 一般用户不懂.
7、数据库未来产品迭代如何修复这个坑
- 希望内核层支持行迁移功能. 并且可以配合autovacuum, vacuum来进行使用.
- 希望内核层支持在线收缩表空间功能: pg_repack. 降低长期持有排他锁影响业务(因为膨胀表通常就是被频繁更新的表, 排他锁会堵塞所有的sql).
- 希望内核能尽量避免膨胀. 例如: 使用类似undo的回滚段代替多版本, 数据文件就不容易膨胀. 或者根据负载自动整理碎片(行迁移, 释放末尾块).
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.