资讯动态

PostgreSQL物理备份利器pg_basebackup实战指南

发布时间:2026/10/14 9:45:33 来源:尧图企业网站定制
你第一次接触pg_basebackup的时候是不是跟我一样心里先打鼓这么重要的备份操作一条命令真能把整个数据库集群都搬走我在生产环境里第一次用它给主库做全量基础备份、顺带把流复制备库搭起来之后这个疑虑就彻底打消了。作为PostgreSQL官方内置的物理备份工具pg_basebackup不需要额外装插件不需要停库直接在运行中的主库上就能拿到一份一致性的全量数据快照既能用来恢复又能用来搭建高可用环境。这篇东西我把自己的使用经验、参数踩坑、排查记录都整理进来给正在研究备份方案或者准备搭备库的朋友一个参考。1. 先搞明白它到底做了什么1.1 它不是“拷贝文件”那么简单很多人误以为pg_basebackup就是把数据目录cp一份其实没那么简单。数据库在运行的时候数据文件是一直在变的物理拷贝同一时刻的文件列表可能有的文件拷的是10点的状态、有的文件拷的是10点零5秒的状态彼此之间不一致这种备份没法直接用。pg_basebackup的思路是在备份开始的时候先跟主库协调一个checkpoint检查点位置然后边拷贝数据文件边记录从检查点之后产生的所有WAL日志。等数据文件拷贝完了再把这段WAL补上最终得到“某个时刻之后、所有变更都已应用”的完整数据集。简单说它保证你拿到的不是一堆散文件而是一个自洽的、能正常启动的数据库集群。1.2 和pg_dump的本质区别PostgreSQL的备份工具分两派pg_dump是逻辑备份导出的是SQL语句或特定格式的数据文件粒度可以细化到某张表、某个Schema跨版本恢复能力强但恢复速度慢pg_basebackup是物理备份备份的是整个数据目录的二进制文件包含所有数据库、角色、表空间、配置恢复的时候直接把文件放回去就能启动速度极快。举一个我实际遇到的场景某次测试环境要模拟生产数据生产库有800GB左右pg_dump导出来光传输就花了快一天恢复的时候又要执行几千个SQL又花了大半天。后来改成pg_basebackup拉到测试机整个传输加恢复不到一个小时就搞定了。这就是物理备份的底气。1.3 它解决的三个核心痛点第一个痛点是“不停机”。主库业务不能停pg_basebackup在热备模式下不影响正常读写备份过程会带来一定IO压力这个是后话。第二个痛点是“一致性”不依赖第三方工具官方本身就保证备份集是可恢复的。第三个痛点是“搭备库”的效率一条命令出来备库的数据文件、恢复配置全都就绪了特别是配合-R参数收工极快。2. 核心参数逐个拆解2.1 连接相关-h、-p、-U这三个参数是最基础的连接选项-h指定主库地址-p指定端口默认5432-U指定连接用户名。需要特别注意的是执行备份的账号必须有REPLICATION权限普通的读写账号即使有SUPERUSER权限也不一定能通过复制协议连接这个后面在权限排查里细说。连接时还有两个隐含行为容易被忽略第一pg_basebackup走的是复制协议不是普通的libpq查询协议所以pg_hba.conf里面要配replication类型的条目才能放行第二它要求主库和备份目标机器的PostgreSQL主版本一致比如主库是15备份机的工具版本也必须是15的大版本小版本可以不同。2.2 输出与存储-D、-F、-X-D指定目标目录也就是备份输出到哪里。这里有个小坑如果目录已存在且不为空pg_basebackup会报错。所以要么指定一个不存在的路径要么用空目录。我的习惯是每次备份都新建一个带时间戳的目录既不会冲突也方便后续归档管理。-F指定输出格式两种选择pplain和ttar。plain格式就是直接把所有文件平铺输出到目标目录恢复的时候最方便tar格式会将数据和WAL分别打成tar包适合归档保存但恢复前要先解包。生产环境我做本地备份习惯用plain做异地归档会用tar。-X参数决定WAL日志怎么处理这也是最容易踩坑的地方之一。三个可选值none表示不包含WAL日志这种备份不能用于恢复等于废的fetch表示在备份完成后从主库拉取所需的WAL文件要求主库的wal_keep_size要够大或者归档已经配置好否则可能拉不到stream表示在备份进行的同时通过复制流实时接收WAL这种方式最稳。我强烈建议你平时就固定用-X stream几乎不会出现WAL缺失的问题。提示如果用了-F t打包格式WAL会自动被放到一个单独的pg_wal.tar包里如果你又指定了-X fetch需要保证主库上WAL还没被回收否则备份中途就报错中断。2.3 复制槽与自动恢复配置-C、-S、-R-C和-S配合使用可以在主库上自动创建一个复制槽replication slot比如-C -S bk_slot_01。复制槽的作用是告诉主库“我这个备库还没追完的WAL不能删”从根本上避免WAL被回收导致的断档问题。代价是如果备库长期断连主库的WAL会一直堆积把磁盘撑爆所以用槽必须配套监控。-R是我个人非常喜欢的一个参数它会在备份出来的数据目录里自动生成流复制所需的配置信息。在PostgreSQL 12以前生成的是recovery.conf12及以后版本生成的是standby.signal文件加连接主库的参数。这个参数直接把“备份”和“变成备库”这两个步骤打通了备份完改一行配置就能启动一个真正的备库。2.4 进度与校验-P、-v、-l、--manifest-P显示备份进度-v输出详细日志这两个配合起来能让你清楚看到当前在传输哪个文件、整体完成了百分之多少。大库备份的时候这种反馈特别重要至少你知道程序还活着并且进展到了哪一步心里不慌。-l给备份集打个标签这个标签会写进backup_label文件恢复的时候能看到这个备份是什么时候、什么目的创建的。不要嫌麻烦关键时刻这个标签能帮你快速找到需要的那份备份。--manifest是PostgreSQL 13新增的参数会在备份目录里生成一个清单文件记录所有文件的路径、大小、校验和。恢复之前可以用pg_verifybackup校验备份集完整性这算是给备份上了一道保险。磁盘充裕的话我建议都加上。2.5 参数速查表参数作用关键注意点-h主库主机地址备库不能用 localhost 连自己-p主库端口默认5432-U复制账号必须拥有REPLICATION权限-D目标目录已存在的非空目录会报错-F输出格式 p/t归档用t恢复方便用p-XWAL获取方式 none/fetch/stream强烈建议stream-C创建复制槽需配合-S指定槽名-S复制槽名称注意主库槽数量上限-R生成备库恢复配置搭备库必加-P显示进度建议开启-v详细输出排障时必开-l备份标签标识备份用途--manifest生成校验清单配合pg_verifybackup使用3. 实战一条命令搭建流复制备库3.1 主库前置配置搭备库之前主库要改几处配置。首先是postgresql.conf里必须明确写wal_level replica或者logical级别默认是replica基本不用动同时要设置足够大的max_wal_senders这个值决定能同时存在多少个WAL发送进程。比如你准备搭两个备库加上备份用的连接建议至少设到5以上。其次是pg_hba.conf必须要添加一条允许复制协议连接的规则例如# 允许某个网段的主机用 repl_user 账号做复制 host replication repl_user 192.168.1.0/24 md5不要忘了复制协议和普通连接在pg_hba.conf里是分开匹配的如果你只配了普通数据库连接规则主库会直接拒绝备份请求。配置完这两处后重启主库生效。3.2 创建复制账号复制账号推荐单独建一个不要直接拿超级管理员到处用。创建语句CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 你的强密码;这里REPLICATION是权限关键字没有它就算有SUPERUSER也可能在复制协议下被拒实际上超级用户是可以连的但生产环境不应该这么做。账号建好之后顺便确认一下max_replication_slots的值如果要用自动创建复制槽这个值必须大于0。3.3 执行备份命令全部前置准备好之后在备库服务器上执行pg_basebackup -h 192.168.1.10 -p 5432 -U repl_user \ -D /var/lib/postgresql/15/main \ -X stream -P -v -R -C -S standby_slot_01这条命令拆开来看连接到主库用复制账号把基础备份输出到备库的数据目录WAL用流式方式接收显示进度和详细日志自动生成备库恢复配置并在主库上创建名为standby_slot_01的复制槽。第一次执行的时候-P参数输出的进度条会让我这种没耐心的人很受用你能看到每个表空间文件的传输百分比。整个过程取决于数据量大小几十GB的库大概几分钟到十几分钟。命令跑完后立刻检查两件事一是确认目标目录里生成了standby.signal文件二是查看postgresql.auto.conf文件里面应该已经写好了primary_conninfo连接信息。这两个文件就是-R参数的功劳没有它你得手动建文件、手动写连接串。3.4 启动备库并验证接下来启动备库pg_ctl -D /var/lib/postgresql/15/main start启动日志里如果出现database system is ready to accept connections且是只读模式说明基本成功了。注意备库是只读的不能直接写数据这是流复制正常现象。在主库上查状态SELECT * FROM pg_stat_replication;如果看到一行记录state字段是streamingsync_state根据配置是async或sync说明备库已经在正常接收WAL了。此时再到备库上执行一个只读查询比如查最新事务ID能看到数据是持续在更新的。3.5 验证数据的实时性我习惯做一个更直观的验证在主库建一张测试表插入几行数据不提交的思路不行要提交。然后在备库上查询这张表的数据能看到说明复制链路完全可用。注意备库查询会有很小延迟特别是异步复制模式下插进去立即查一般是没问题的但如果主库写入负荷很大备库延迟可能到几秒甚至更多这也是异步复制的常态。4. 备份规划从单机备份到归档策略4.1 本地临时备份的正确姿势如果你只是想临时拉一份全量数据做分析或者迁移不需要长期归档最简单的方式pg_basebackup -h 127.0.0.1 -p 5432 -U repl_user \ -D /data/backup/$(date %Y%m%d) \ -F p -X stream -P -v这个方案备份出来的就是完整数据目录直接把这个目录打包传走也行tar格式做成归档也行。我通常搭配-l参数加一个标签比如-l backup_for_test_restore方便以后查看meta信息。4.2 定期全量备份脚本的思路定时任务里跑pg_basebackup要注意几个细节。首先备份目录要做保留策略比如保留最近7天的全量备份加当天的WAL老备份自动删除防止磁盘被塞满。其次备份前最好检查主库的复制连接数上限避免备份任务和其他备库抢WAL发送进程。再者每次备份完要做一次恢复演练不能只生成备份文件就完事。一个简化版的备份脚本思路BACKUP_BASE/backup/pgsql DATE_TAG$(date %Y%m%d_%H%M%S) pg_basebackup -h $PRIMARY_HOST -U repl_user \ -D $BACKUP_BASE/$DATE_TAG -F p -X stream -P -v -l daily_backup_$DATE_TAG # 校验备份集 pg_verifybackup $BACKUP_BASE/$DATE_TAG # 清理超过7天的备份 find $BACKUP_BASE -maxdepth 1 -type d -mtime 7 -exec rm -rf {} \;思路很简单但是做定时任务的人都知道“重启后能不能自动跑”“磁盘满了会怎样”“备份失败要不要报警”这些问题不提前想好迟早会翻车。4.3 恢复流程最后一公里的演练备份做得再好不演练恢复等于没做。恢复流程其实很简单把备份目录拷贝到目标机器修改配置文件的监听地址和端口然后正常启动。如果在备份时用了-R参数恢复前要把standby.signal文件删掉否则启动后还是以只读备库模式运行而不是一个可写的主库。另外一个关键点恢复到的机器主版本必须和备份时一致跨大版本不能直接用pg_basebackup的备份集恢复。小版本差异一般没问题但要考虑二进制格式和工具链的兼容性我建议恢复机的版本不低于备份机的小版本。4.4 归档日志与增量恢复的关系pg_basebackup全量备份加上持续归档的WAL日志就构成了完整的恢复体系。全量备份解决“恢复到某个时间点”的基础WAL归档解决“全量备份之后到故障点之间的增量”。如果你只做全量备份但不保留WAL那最多只能恢复到备份时刻如果保留归档WAL就能做到PITR按时间点恢复甚至恢复到误删数据前的那一秒。在实际的恢复场景里我常用pg_ctl加恢复目标参数的方式比如-r指定恢复标识然后在postgresql.conf或recovery.signal里设置recovery_target_time。这里面的细节很多但不属于pg_basebackup本身的范畴先点到为止。5. 常见问题与排查技巧实录5.1 权限与认证问题有一个报错我几乎每次帮别人排查都会遇到FATAL: no pg_hba.conf entry for replication connection from host 192.168.1.20, user repl_user这个基本上就是pg_hba.conf里没有配replication条目或者条目顺序不对。pg_hba.conf是按顺序匹配的第一条匹配的规则生效所以如果你的host all规则写在前面拦住了复制连接后面的host replication规则就不会生效。解决方法是把复制规则的优先级放高或者确保网络匹配条件清晰无歧义。另一个常见报错是FATAL: replication connections are not allowed in this database这是没指定replication关键字导致的误用检查命令里是否少了什么参数或者账号权限不对。5.2 目录与磁盘空间问题报错pg_basebackup: error: directory /var/lib/postgresql/15/main exists but is not empty不用怀疑目标目录里有内容了。要么换一个新的空目录或者不存在的路径要么清空现有目录。注意pg_basebackup支持往一个已经initdb过的空目录里输出数据但如果是之前残留过数据文件的目录它也不会让你覆盖。磁盘空间不足是备份失败的重灾区。pg_basebackup在开始之前会估算所需空间但实际上数据库里的膨胀、WAL累积都可能让实际占用超过预期。备份过程中如果磁盘满了程序会直接中断而且已经拷贝的部分可能不完整这种备份一定不能用于恢复。我的经验是预留至少数据库实际大小的1.5到2倍空间尤其当-X stream时WAL文件也在同时落地。5.3 WAL获取失败问题使用-X fetch方案时可能会遇到pg_basebackup: error: could not receive WAL files from the base backup: could not find WAL record这说明主库的WAL已经被回收了备库或备份进程需要的WAL段不存在了。为什么我用stream方案基本不会碰到因为流式WAL在备份传输的过程中就实时接收了不需要事后回主库去拉。生产环境我基本都是-X stream只有极特殊情况下才会用fetch那时候我会提前把wal_keep_size调大确保WAL有足够保留窗口。跟WAL相关的还有一个教训如果你用了复制槽且备库长时间断连主库WAL会持续堆积。等发现主库磁盘告警时那个堆积的WAL已经占了上百GB了。所以复制槽不是万能的它解决WAL丢失问题却引入了WAL堆积风险必须有监控。5.4 备份机工具版本不一致报错pg_basebackup: error: could not identify system: got 1 rows and 124 fields, expected 1 rows and 121 fields这种诡异报错通常是主库和备份机的PostgreSQL主版本不一致导致的。比如主库是15版本你本地命令行工具却是14版本协议对不上。解决办法是使用与主库相同主版本的工具或者干脆在备份机上安装同版本的PostgreSQL软件包。5.5 备库启动后一直追不上主库如果备库启动后pg_stat_replication里的state一直是catchup而不是streaming或者replay_lsn迟迟追不上sent_lsn通常有两种原因备库硬件性能太差、主库写入压力极大。这个时候可以先检查备库的磁盘IO和CPU另外看看主库的pg_wal目录里是不是积压了很多WAL要补。如果只是临时性追赶不用太担心等追平就好了如果长期追不上就要考虑提升备库性能或者调整同步策略。5.6 问题速查表现象大概率原因处理建议连接被拒提示pg_hba.conf复制连接规则缺失或顺序不对检查/调整pg_hba.conf并reload提示目录已存在且非空目标目录有残留数据换新目录或清空旧目录提示WAL文件找不到主库WAL被回收或未用stream改用-X stream或调大wal_keep_size工具版本报错主备版本不一致统一主版本工具备库启动后只读无法写入这是备库正常状态确认standby.signal文件和恢复配置备份中断显示磁盘满目标盘空间不足预留1.5-2倍空间检查监控主库磁盘暴涨复制槽导致WAL堆积定期清理失效槽或监控复制状态6. 备份策略的进阶思考与个人心得6.1 全量备份的频率怎么定不同的业务对恢复点目标要求不一样有的容忍丢10分钟数据有的要求最多丢10秒。pg_basebackup全量备份的频率决定了两份全量备份之间的WAL归档需要保留多久。比如你每天凌晨做一次全量备份那WAL归档至少保留24小时才能支持任意时间点的恢复。如果你的恢复点目标要求是1小时那全量备份可能要增加到每小时一次但全量备份的成本和WAL归档的成本需要做权衡。我见过一些极端情况有人以为什么都用pg_basebackup就够了结果恢复的时候发现全量备份是昨天凌晨的想要恢复到昨天下午4点但WAL归档只保留了最近2小时中间的WAL已经没了只能干瞪眼。所以全量备份和WAL归档的保留周期必须一起规划而不是分开各自为政。6.2 备份期间的性能影响pg_basebackup不是完全没有副作用的。备份过程中它会大量读取数据文件产生不小的IO压力同时在主库上做checkpoint可能会触发一次集中的刷盘如果开启了-P进度输出还会额外产生网络传输。对大库而言备份期间可能让主库的查询延迟明显上升和生产高峰时段叠加就更明显。我的实践是全量备份尽量安排在业务低峰期并且错开和其他定时任务比如报表生成、数据归档的IO竞争。如果条件允许可以给pg_basebackup限定IO优先级或者从流复制备库上拉备份把压力转移到备库。这一点很多文档都没特别强调但对生产环境很关键。6.3 校验备份比备份更重要备份文件生成了不等于能恢复。文件损坏、传输中断、目录权限不对任何一个环节出错都会导致恢复失败。PostgreSQL 13以后提供的--manifest和pg_verifybackup是我认为最有价值的新特性之一它能通过清单文件逐一校验备份集内的文件完整性和校验和。每次做完整备份之后花十几秒跑一遍校验比真出事的时候再面对一堆不可用备份强得多。这十几秒的高性价比是我个人最想推荐给所有数据库运维同行的习惯。6.4 自动化备份要配套监控告警备份任务本身要纳入监控体系。没有告警的备份计划等于没有备份计划因为备份失败你不会知道等到恢复的时候才发现备份早就断了那种绝望感相信经历过的人都不想再来一次。监控至少应该覆盖备份任务是否成功完成、备份集是否可以校验、备份占用的磁盘空间是否接近阈值、主库WAL堆积是否异常。这里面的思路其实跟写代码很像把异常路径都考虑进去做好fail-fast和fail-alert。备份任务失败要能主动报警不是等到第二天人工检查才发现昨晚全挂了。6.5 我个人的备份习惯总结我现在的默认做法是每天的凌晨低峰期对主库执行一次pg_basebackup全量备份输出格式用plainWAL用stream模式备份时开启--manifest做校验清单保留最近7天版本同时持续开启WAL归档并且归档保留整个全量备份周期。每次全量备份完成后顺手用pg_verifybackup做一次快速校验一切正常才认为当天备份任务真正完成。这套流程跑下来用了很久都没出过大的恢复事故中间踩过的版本坑、WAL坑、权限坑基本都沉淀在上面了。如果你刚开始用pg_basebackup别迷信任何一篇博文包括这篇直接拿一个测试实例跑一次全量备份、删点数据、用备份恢复一次比看十篇文章都有用。只有亲手恢复过你才会理解备份的意义也才会对pg_basebackup的每一个参数有切身体会。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑