PostgreSQL 13中VACUUM FULL进程终止后磁盘未释放原因及回收方法
终止VACUUM FULL后磁盘空间未释放的原因
- VACUUM FULL的核心逻辑是生成一份全新的表/索引副本文件,逐行写入原表的可见有效数据,待全量拷贝、校验全部完成后,才会替换原有的旧数据文件,最后删除旧文件。你手动终止进程时,这部分已经写入了150GB数据的临时副本文件还没走到删除流程,会直接残留在数据目录中。
- 类Unix操作系统的文件回收规则是:只有当一个文件的所有硬链接被删除、且所有持有该文件句柄的进程全部退出后,文件占用的磁盘块才会被真正回收。如果终止VACUUM FULL时,对应的PostgreSQL后端工作进程没有正常退出成为僵死进程,或是checkpointer、后台writer等进程仍然持有这个临时文件的句柄,哪怕文件已经被标记为删除,空间也不会返还给操作系统。
- PostgreSQL对运行中生成的临时文件、中间文件的自动清理逻辑,仅会在进程正常退出、实例重启的恢复阶段触发。进程被异常终止的运行状态下,数据库不会主动扫描数据目录清理残留的临时文件,这部分空间就会一直被占用。
回收150GB残留空间的可操作方案
按操作风险从低到高排序,优先尝试前面的方案:
- 第一步先排查僵死进程的句柄占用,在操作系统层执行
lsof | grep deleted | grep postgres,如果输出结果中存在大小和150GB匹配、路径位于PostgreSQL数据目录下的已标记删除文件,记录对应的进程PID,确认是无业务关联的僵死postgres进程后,执行kill -9 对应PID,进程退出后操作系统会自动回收这部分磁盘空间,操作不会影响正常运行的数据库业务。 - 如果上一步没有找到匹配的已删除文件句柄,先登录数据库执行
CHECKPOINT;强制刷盘,再连接到执行VACUUM FULL的目标业务库,执行SELECT * FROM pg_ls_tmpdir();查看当前库下残留的临时文件,确认文件生成时间、大小和本次中断的VACUUM FULL任务匹配后,执行数据库内置的文件删除函数清理:SELECT pg_remove_file(name) FROM pg_ls_tmpdir() WHERE size > 100*1024*1024*1024;,注意执行前必须确认文件是本次任务残留的,不要误删其他运行中任务生成的临时文件。 - 如果前两步操作都没有释放空间,选择业务低峰期重启PostgreSQL实例即可。数据库启动时的崩溃恢复流程会自动扫描数据目录,清理所有不属于当前运行实例的临时文件、废弃中间文件,重启完成后残留的150GB空间就会被操作系统回收。
注意:不要直接在操作系统层使用rm命令删除PostgreSQL数据目录下你无法确认用途的文件,避免误删正常的表、索引数据导致数据库损坏不可用。
内容的提问来源于stack exchange,提问作者Siddheshwar Soni
相关产品推荐
相关产品推荐

