PostgreSQL的物理备份(基础备份)是搭建流复制、做PITR时间点恢复的基础。而提到物理备份,就绕不开两个关键函数:pg_start_backup和pg_stop_backup。很多刚接触PostgreSQL运维的朋友直接用pg_basebackup工具一把梭,能跑通但不知道背后发生了什么,一旦备份出问题或者遇到版本变更后的函数废弃警告,就束手无策了。这篇文章就围绕这两个函数,把热备份的完整机制讲透。

pg_start_backup到底做了什么
pg_start_backup的作用是通知PostgreSQL:我要开始一次基础备份了。调用它之后,数据库会做几件关键的事情。第一,强制切换一次WAL段文件,并在checkpoint之后确保备份的起点有一个明确的日志位置。第二,在数据目录(PG 9.6之前)或内存中(PG 9.6及之后的非排他模式)记录备份开始的时间点和对应的WAL位置。第三,开启full_page_writes机制,保证在备份期间WAL中会记录数据页的完整镜像,这样备份文件中那些“半新半旧”的页面才能通过WAL重放来修复。
这里有个非常重要的概念需要理解:为什么备份出来的数据文件是不一致的?因为备份数据文件时,PostgreSQL不会暂停写入,各个文件被复制的时间点不同,有的文件是备份开始时复制的,有的是几小时后复制的,它们之间天然不一致。而pg_start_backup通过强制记录起点WAL位置,配合备份期间归档的WAL日志,就能在恢复时用日志把这个不一致“抹平”。这也是为什么热备份期间数据库可以正常读写,不影响业务。
在PostgreSQL 9.6之前使用的是排他模式,函数签名是pg_start_backup('label'),它会直接在数据目录写一个backup_label文件,备份期间如果数据库崩溃,重启时会因为backup_label存在而尝试从备份起点恢复,这是个隐患。9.6之后推荐非排他模式:
-- PostgreSQL 9.6至14的非排他模式用法
SELECT pg_start_backup('backup_20240101', false, false);
-- 第一个参数:备份标签,用于标识这次备份
-- 第二个参数:是否立即执行fast checkpoint
-- 第三个参数:false表示非排他模式(9.6起新增)
非排他模式下,backup_label的信息不再写文件到数据目录,而是保存在内存和pg_stat_progress_backup视图中,由pg_stop_backup在结束时返回给你,需要备份工具自己保存,安全性大大提高。
pg_stop_backup与backup_label文件的生成
数据文件复制完成后,必须调用pg_stop_backup来结束备份。这个函数同样做了几件关键的事:确定备份结束的WAL位置,强制再切换一次WAL段并归档,然后返回(非排他模式)backup_label和tablespace_map的内容,供备份工具写入备份集目录。
为什么要强制切换WAL并等待归档?因为恢复备份时,必须要有从备份起点到终点之间完整的WAL日志链。如果最后一段WAL没有归档成功,这个备份就是残缺的,恢复时会在中途卡住。所以调用pg_stop_backup时,如果开启了归档(archive_mode=on),它会一直等待最后一段WAL归档完成才返回;如果归档命令有问题,这个函数就会一直挂起,这是运维中非常常见的故障点。
-- 结束非排他备份(9.6至14) SELECT * FROM pg_stop_backup(false); -- 返回多列结果: -- labelfile:backup_label文件内容,需写入备份目录 -- spcmapfile:tablespace_map内容(如有表空间) -- lsn:备份结束的WAL位置
backup_label文件是整个备份的“身份证”,里面记录了检查点位置、WAL起始LSN、备份开始时间和标签名。恢复时,PostgreSQL读取到这个文件,就知道从哪个WAL位置开始重放。把它弄丢或者篡改,备份就基本废了。
需要注意的是,从PostgreSQL 15开始,pg_start_backup和pg_stop_backup这两个函数被正式移除(14版本就已标记废弃),替代者是pg_backup_start和pg_backup_stop,参数语义基本一致,只是名字更直观,并且不再需要第三个参数来区分排他模式,因为排他模式已经被彻底删除了。
手动执行一次完整的基础备份
理解了原理,我们手动走一遍流程,这对排查备份问题很有帮助。前提条件:wal_level设置为replica或logical,archive_mode开启并配置好archive_command。
-- 1. 开始备份
psql -c "SELECT pg_backup_start('manual_backup', false);"
-- 2. 复制数据目录(排除不需要的文件)
tar --exclude='pg_wal/*' --exclude='postmaster.pid' \
-czf /backup/base.tar.gz $PGDATA
-- 3. 结束备份并获取labelfile
psql -c "SELECT * FROM pg_backup_stop();"
-- 4. 将返回的labelfile内容保存为备份目录中的backup_label文件
有一个细节要注意:复制数据目录时通常排除pg_wal目录下的WAL文件,因为恢复所需的WAL会从归档目录获取。如果网络传输中断导致备份中途失败,务必调用pg_backup_stop正常结束,否则备份会话悬空,可能一直持有资源。非排他模式下如果连接断开,备份会自动中止,这也是非排他模式更安全的原因之一。
常见报错整理:报“archive_command failed”说明归档配置有问题,检查归档目录权限和脚本;pg_stop_backup长时间不返回,多半是archive_command挂了或归档目的地满了;报“functions are not supported”通常是版本问题,15以后要换成新函数名。
最佳实践与总结
日常生产环境,除非有特殊定制需求,否则优先使用pg_basebackup或第三方工具如pgBackRest、Barman,它们的底层正是通过这对函数(或新版函数)实现的,但额外处理了并发一致性、压缩、校验和增量化等细节。手动调函数的意义在于理解原理和应急场景。
几个实践建议:备份标签里带上主机名和时间方便追溯;备份完成后务必验证,可以把备份恢复到测试实例确认可用;监控备份耗时和WAL归档延迟,备份期间归档堆积往往是磁盘或归档脚本故障的信号;定期演练PITR恢复流程,没经过恢复验证的备份不能算有效备份。
总结一下:pg_start_backup标记起点并触发checkpoint,pg_stop_backup标记终点并确保WAL归档完整,中间复制的数据文件虽然不一致,但依靠备份期间积累的WAL日志可以在恢复时达到一致状态。这就是PostgreSQL物理热备份的全部核心逻辑,理解了它,流复制搭建、PITR恢复这些进阶操作都会变得清晰起来。
PostgreSQL热备份pg_start_backuppg_stop_backup修改时间:2026-09-09 02:12:42