pg_verifybackup
pg_verifybackup 是 PostgreSQL 13 引入的一个客户端工具,用来验证由 pg_basebackup 产生的基础备份是否完整。它的校验依据是备份过程中服务端生成的 backup_manifest(备份清单)文件:清单里记录了每个数据文件的路径、大小和校验和,以及恢复这份备份所需的 WAL 范围。工具会把磁盘上的实际内容与清单逐项比对。
为什么需要这样一个工具?因为在“备份成功”和“备份可用”之间,有一道很容易被忽略的鸿沟。pg_basebackup 正常退出只说明它把数据读完了,但磁盘坏道、文件传输截断、人为误删、备份目录被误写,都可能让文件在落盘后发生变化。等到真正需要恢复的时候才发现备份是坏的,代价极高。定期跑一次校验,可以把“备份不可用”这件事提前暴露在平时。
需要明确的是:pg_verifybackup 的校验不能覆盖运行中的服务端在真正使用这份备份时会做的全部检查。官方明确指出,即便使用了这个工具,仍然应当做实际的试恢复,确认恢复出来的数据库能正常工作且数据正确。它的价值在于能发现存储问题或人为错误导致的大量常见故障,而不是替代演练。
从阶段十四的上下文看,这一页处在“复制槽与备份管理”中,紧接复制槽之后:复制槽解决的是“在线复制不断线”,pg_verifybackup 解决的是“离线备份是否可信”。两者都是备份体系里“防止意外”的环节。
前置知识
建议先阅读:复制槽(Replication Slot)
基础概念
backup_manifest 从哪来
backup_manifest 由服务端在备份期间生成,随备份一起写入备份目录。它不是 pg_verifybackup 自己算出来的,也不是事后补的——这一点很关键:如果备份过程中没生成清单,事后就无法校验。
清单的最典型来源是 pg_basebackup;使用底层备份 API(pg_backup_start / pg_backup_stop)的第三方备份工具也可以拿到清单内容。因此“有没有清单”是判断一份备份能否被 pg_verifybackup 校验的前提。
清单的顶层字段
清单是一个 UTF-8 编码的 JSON 文档,顶层是一个对象,包含以下键:
| 键名 | 含义 |
|---|---|
PostgreSQL-Backup-Manifest-Version | 清单格式版本,整数。PostgreSQL 17 起为 2,更早版本为 1 |
System-Identifier | 备份来源实例的系统标识符。仅在清单版本为 2 时存在 |
Files | 对象列表,每项描述备份中的一个文件 |
WAL-Ranges | 对象列表,每项描述一段必须可读的 WAL 范围 |
Manifest-Checksum | 位于清单文件的最后一行,是对其前面所有行的 SHA-256 校验和 |
Manifest-Checksum 使用固定算法(SHA-256)而非可配置算法,目的是让客户端能够增量解析清单。
Files 列表中的单个文件对象
每个文件对象包含以下键:
| 键名 | 是否总是存在 | 含义 |
|---|---|---|
Path | 通常存在 | 相对于备份根目录的路径 |
Encoded-Path | 条件存在 | 当路径不是合法 UTF-8 字符串,或用户要求全部使用编码路径时,改用十六进制字符串表示 |
Size | 总是存在 | 文件期望大小(整数) |
Last-Modified | 总是存在 | 备份时服务端报告的文件最后修改时间。注意:该字段不被 pg_verifybackup 使用,仅供参考 |
Checksum-Algorithm | 启用文件校验和时存在 | 该文件所用的校验算法:CRC32C、SHA224、SHA256、SHA384、SHA512 |
Checksum | 启用文件校验和时存在 | 该文件的校验和,十六进制表示,每字节两位十六进制字符 |
关于 Path 与 Encoded-Path 的取舍:用户自定义表空间中的文件,其路径前两个组成部分是 pg_tblspc 与表空间 OID。路径若非法 UTF-8,则必须用 Encoded-Path。
WAL-Ranges 中的单个范围对象
每个 WAL 范围对象固定有三个键:
| 键名 | 含义 |
|---|---|
Timeline | 该 WAL 范围所属时间线,整数 |
Start-LSN | 使用这份备份时,在该时间线上必须开始重放的 LSN |
End-LSN | 使用这份备份时,在该时间线上可以结束重放的最早 LSN |
LSN 的格式与平时一致:两段十六进制字符(各 1~8 位),中间以斜杠分隔。
通常只有一个 WAL 范围。但如果备份是从备库上做的,且备份期间上游发生提升导致备库切换了时间线,就可能出现多个范围,每个对应不同时间线;同一时间线不会出现多个范围。
校验的四个阶段
pg_verifybackup 的校验流程是固定的四步:
- 读清单。若清单不存在、无法读取、格式损坏、与备份目录
pg_control中的系统标识符不匹配,或未通过自身校验和验证,则直接以致命错误终止。 - 比对文件列表。检查磁盘上实际存在的文件与清单中“服务端打算发送的文件”是否一致。会检出错失文件与多余文件(但有若干例外,见后文)。
- 校验校验和。对所有文件计算校验和并与清单中的值比对,不一致则报错。第二步已报错的文件不会再进入这一步;被忽略的文件在这一步同样被忽略。
- 校验 WAL。依据清单中的 WAL 范围,确认恢复所需的 WAL 记录确实存在、且能被读取和解析。实现方式是调用
pg_waldump解析这些记录,并带上--quiet参数,使pg_waldump只输出错误、不输出其他内容。
第 4 步不能发现所有问题:官方明确举例——一个能产生校验和正确但内容荒谬的 WAL 记录的服务端 bug,是无法通过这种方式检测出来的。因此这一步的结论应理解为“没有明显问题”,而不是“绝对安全”。
被忽略的文件
在文件比对阶段,有些文件的“存在 / 缺失 / 被修改”会被忽略:
postgresql.auto.confstandby.signalrecovery.signal
原因是这三个文件在制作备份的过程中很可能被创建或修改,属于预期行为。
同时,工具不会对备份目录中的 backup_manifest 本身报“多余文件”,也不会抱怨 pg_wal 里的任何内容,尽管这些文件并不在清单中列出。
另外需要注意:只检查文件,不验证目录是否存在。目录的影响是间接的——如果某个目录缺失,它应包含的文件必然也会缺失,从而在文件层面被发现。
与 pg_basebackup 的关系
pg_verifybackup 是 pg_basebackup 的配套工具,二者共享清单格式。但两者的选项集合并不相同,容易混淆的一点是:
--manifest-checksums/-c是pg_basebackup的选项,用于在制作备份时选择校验算法。pg_verifybackup没有-c这个选项。
因此脚本中不要给 pg_verifybackup 传 -c,否则会因未知选项而失败。
WAL 校验的版本与格式限制
- WAL 校验是版本相关的:必须使用与被检查备份对应的那个版本的
pg_verifybackup(因而也是对应版本的pg_waldump)。用错版本会得到不可靠的结果。 - 相比之下,数据文件的完整性检查对版本不敏感,可以在任意能生成
backup_manifest的服务端版本上使用。 - 当前的 WAL 校验仅支持 plain 格式的备份。若备份是 tar 格式,应使用
-n, --no-parse-wal选项。
冗余的 WAL 不会被检查
如果备份目录中还存在恢复这份备份不需要的额外 WAL 文件,pg_verifybackup 不会检查它们。若确实需要检查,可以另外单独调用 pg_waldump。
语法与用法
基本用法
pg_verifybackup /var/lib/pgsql/backup/20260920参数直接给备份目录路径。
常用选项
| 选项 | 长选项 | 作用 |
|---|---|---|
-e | --exit-on-error | 一旦发现问题立即退出;不加则持续检查并汇报所有问题 |
-F format | --format=format | 指定备份格式,p/plain 或 t/tar |
-i path | --ignore=path | 比对文件列表时忽略指定文件或目录(相对路径),可多次指定 |
-m path | --manifest-path=path | 使用指定位置的清单文件,而非备份目录根下的那个 |
-n | --no-parse-wal | 不尝试解析恢复所需的 WAL 数据 |
-P | --progress | 显示进度报告(在校验和阶段输出);不能与 --quiet 同时使用 |
-q | --quiet | 校验成功时不输出任何内容 |
-s | --skip-checksums | 不校验数据文件校验和;仍检查文件是否存在及大小,速度更快 |
-w path | --wal-directory=path | 从指定目录而非 pg_wal 解析 WAL 文件 |
-V | --version | 输出版本并退出 |
-? | --help | 输出帮助并退出 |
校验 plain 格式备份
pg_verifybackup -e /var/lib/pgsql/backup/20260920校验 tar 格式备份
pg_verifybackup -n -F tar /var/lib/pgsql/backup/20260920由于 WAL 校验只支持 plain 格式,tar 备份需要显式加 -n。
清单放在备份目录之外
pg_verifybackup -m /secure/manifest/backup_manifest.20260920 /var/lib/pgsql/backup/20260920把清单单独存放可以防止它被误改——但也意味着必须确保清单与备份的配对关系不搞错。
忽略人为添加的文件并跳过校验和
pg_verifybackup --ignore=note.to.self --skip-checksums /var/lib/pgsql/backup/20260920--ignore 的路径必须是相对路径;若指定的是目录,则影响该目录下的整棵子树。
从独立位置解析 WAL
pg_verifybackup -w /mnt/wal_archive /var/lib/pgsql/backup/20260920当备份与 WAL 归档分开存放时,用 -w 指向归档目录。
用于脚本的静默模式
if pg_verifybackup -q /var/lib/pgsql/backup/20260920; then
echo "verify ok"
else
echo "verify failed" >&2
exit 1
fi-q 只在成功时不输出内容;失败时仍会输出错误信息,适合放进自动化流程。
详细说明
为什么要有清单这一层间接引用
设想没有清单的世界:校验工具只能检查“文件能否被打开、大小是否为 0、tar 能否解开”。这些检查相当弱——一个被覆盖了中间 100KB 的文件,大小可能完全没变,tar 也能正常解开,但数据已经错了。
清单引入了两组关键信息:每个文件的大小与校验和,以及“恢复必须读到哪些 WAL”。前者让内容级比对成为可能,后者让“备份能否被重放”这件事第一次可以在恢复之前被验证。这是 pg_verifybackup 相对一般文件完整性检查的核心价值。
阶段一:清单自身也要可信
第一步就校验清单,逻辑上是必要的:如果清单本身被篡改,后面所有比对都建立在错误基准上。
失败的情形包括清单不存在、不可读、格式损坏、与备份目录 pg_control 的系统标识符不匹配、自身校验和不通过。其中“系统标识符不匹配”这一项尤其防呆:它能在一定程度上防止把 A 实例的备份和 B 实例的清单配错。不过要注意,System-Identifier 字段只在清单版本 2(PostgreSQL 17 起)中存在,因此这项检查在版本 1 的清单上如何体现,需要以实际版本文档为准。
Manifest-Checksum 是最关键的一道防线:它位于文件最后一行,是前面所有行的 SHA-256。任何对清单内容的修改都会导致该校验和不匹配。
阶段二:文件列表比对
这一步把“清单里写了有什么”和“磁盘上实际有什么”对齐:
- 清单里有、磁盘上没有 → 缺失文件(报错)。
- 磁盘上有、清单里没有 → 多余文件(报错),但
backup_manifest本身与pg_wal内的内容例外。 - 大小不一致 → 报错。
被显式忽略的只有 postgresql.auto.conf、standby.signal、recovery.signal 这三个文件。之所以忽略它们,是因为在制作备份的过程中(例如用 -R 生成备库配置、或恢复脚本预置信号文件),这三个文件被创建或修改是正常的。
--ignore 选项给了使用者一个扩展的“白名单”入口,用于排除自己额外放进去的运维文件(例如 README、校验记录)。但它是一把双刃剑:忽略过多会削弱校验的有效性。
再说一遍容易误解的一点:目录不参与比对。工具只检查文件。若一个目录整体丢失,其下所有文件都会缺失,从而以“缺失文件”的形式暴露出来。
阶段三:校验和比对
这一步读取每个文件的内容、按清单中记录的算法计算校验和,与清单中的值比对。清单中每个文件记录了 Checksum-Algorithm 和 Checksum 两个字段;当前同一次备份中所有文件使用相同算法,但格式上允许未来变化。
支持的算法是 CRC32C、SHA224、SHA256、SHA384、SHA512。这里存在一个工程取舍:CRC32C 快但抗碰撞能力弱,SHA 系列慢但更强。大备份环境下如果校验耗时成为瓶颈,--skip-checksums 提供了一个“只查存在性与大小”的快速档位——代价是放弃内容级校验。
需要注意:--skip-checksums 只是跳过校验和,文件的存在与大小仍会检查。它的适用场景是“快速初筛”,而不是“最终验收”。
阶段四:WAL 可解析性校验
这一步依据 WAL-Ranges 中的 Start-LSN 与 End-LSN,确认恢复所需的那段 WAL 记录确实存在且可解析。实现方式是调用 pg_waldump,并带 --quiet。
需要理解它的边界:
- 它能发现缺失的 WAL 文件。
- 它能发现内部校验和不匹配的 WAL 记录。
- 它不能发现“校验和正确但语义荒谬”的记录(例如服务端 bug 产生的错误操作)。
还有两点限制:WAL 校验是版本相关的;WAL 校验仅支持 plain 格式。因此对 tar 备份应加 -n,或先解包再校验。
-w 与 pg_wal 的差别
默认情况下,pg_verifybackup 在备份目录的 pg_wal 中查找 WAL。但真实的运维场景常常把 WAL 归档放在别处(例如网络存储、对象存储的本地挂载点),而基础备份目录里只有少量甚至没有 WAL。
-w 选项就是为这种“备份与 WAL 分离”的布局设计的:指向一个包含 WAL 文件的目录(例如归档目录),让工具在那里解析。
还有一点值得注意:若存在恢复不需要的额外 WAL 文件,工具不会检查它们。这与“WAL 归档是否完整”是两件事——归档的完整性需要另外的手段(例如比对归档文件清单)来验证。
-F 与备份格式
-F p / -F plain:备份就是与源数据目录同样布局的普通文件。这是唯一支持 WAL 校验的格式。
-F t / -F tar:备份由若干 tar 文件组成,可能被压缩。一个合法的 tar 备份包含:主数据目录在 base.tar 中,WAL 文件在 pg_wal.tar 中,每个表空间各有独立的 tar 文件(以表空间的 OID 命名)。若备份被压缩,相应压缩扩展名会附加到各文件名末尾。
由于 tar 格式不支持 WAL 校验,官方建议对 tar 备份使用 -n。
校验耗时与资源占用
校验和阶段需要完整读取备份中的每个文件,因此耗时近似等于“备份总大小 ÷ 磁盘读取带宽”。这是一个典型的 I/O 密集操作,在大备份(数百 GB 到数 TB)上可能持续很久。
现实中的做法是分层校验:
- 每次备份后跑一遍
--skip-checksums的快速检查(检查存在性与大小),成本低。 - 定期(例如每周、或每次全量备份后)跑一次完整校验。
- 对特别关键的备份,在恢复演练中做实际试恢复。
--progress 可以在长时间校验中给出进度反馈,但它与 --quiet 互斥——因为一个要输出进度、一个要求安静。
使用 --exit-on-error 的取舍
不加 -e 时,工具会持续检查并汇报所有发现的问题。这在“诊断一份可疑备份到底坏在哪”时非常有用,因为一次就能拿到完整的问题清单。
加了 -e 则在第一个问题处立即退出。这在自动化流程中更省时间(不必把整个几 TB 的备份读完才失败),但会丢失后续问题的信息。
因此:自动化流水线用 -e,人工排障用默认(不加 -e)。
校验通过意味着什么、不意味着什么
校验通过说明:
- 备份目录中的文件与清单一致(内容、大小)。
- 清单本身可信。
- 恢复所需的 WAL 存在且可解析。
校验通过不说明:
- 这份备份的配置是否正确(
postgresql.conf、pg_hba.conf等仍是备份时的样子,可能不适合目标环境)。 - 恢复后数据业务上正确。
- 服务端不会在恢复过程中因为其他原因失败。
- 存储介质在未来的某个时刻不会坏。
所以官方那句“仍应做实际试恢复”不是客套话,而是校验能力边界的直接结论。
校验失败之后的排查顺序
遇到失败时,可以按阶段倒推:
- 错误提示指向清单本身(缺失、损坏、系统标识符不匹配)→ 先确认清单与备份是否配套,以及清单是否被误改。
- 报“缺失文件” → 检查备份是否被部分删除、复制是否中断。
- 报“多余文件” → 检查是否有人往备份目录里写了东西;若是预期的运维文件,用
--ignore。 - 报“大小不一致” → 常见于传输截断。
- 报校验和不匹配 → 内容被破坏,通常需要重新制作备份。
- 报 WAL 相关错误 → 检查 WAL 归档是否完整、
-w是否指向正确目录、版本是否匹配。
一个原则:任何“内容被破坏”的结论,都应当优先考虑重做备份,而不是试图修复这些文件。
与 pg_checksums 的分工
pg_checksums 校验的是数据目录中数据页的校验和,用于发现存储层面的静默损坏;它作用于一个可运行(但必须干净关闭)的实例数据目录,且需要实例在初始化时启用了 data checksums。
pg_verifybackup 校验的是备份与清单的一致性,作用于一份备份副本,不需要运行实例。
两者角度完全不同,不能互相替代:
- 想知道“当前在线实例的数据页有没有被静默损坏”→
pg_checksums。 - 想知道“这份备份是不是完整的、能不能用”→
pg_verifybackup。
与 pg_basebackup 校验选项的配合
在制作备份时,pg_basebackup 提供了与清单校验和相关的选项,用于决定清单中记录何种校验算法。选更强的算法会让之后每次校验都更慢,但发现问题的能力更强;选 CRC32C 则反之。
这是一个需要在“校验频率 × 备份大小 × 存储可靠性”之间做的权衡,没有通用最优解。对于校验频繁且备份巨大的场景,CRC32C 通常是更实用的起点;对于容灾要求极高的场景,可以选 SHA 系列。
清单的版本演进
PostgreSQL-Backup-Manifest-Version 目前有 1 和 2 两个值:PostgreSQL 17 起为 2,更早为 1。版本 2 新增了 System-Identifier 字段,这正是“清单与实例标识符匹配检查”的依据。
这意味着:解析清单的自研工具必须同时处理两个版本;只看某个版本的字段集合会导致在另一版本上解析失败。
增量与差异备份语境下的校验
在“全量 + 增量”的备份体系里,校验的对象与策略需要区分:
- 全量备份自带完整清单,可以独立校验。
- 增量备份通常依赖“上一份全量 + 中间若干增量”这一条链,任何一个环节损坏都会让整条链不可用。
因此对增量体系,校验不能只做“每份都过一遍”那么简单,还要验证链的完整性:从基准全量出发,按顺序串联所有增量,确认每一步都能接上。这属于更复杂的工程问题,需要备份软件自身支持。本页讨论的 pg_verifybackup 主要面向单份备份(通常是与 pg_basebackup 配套的全量备份)。
校验结果的记录方式
校验这件事本身需要留痕,否则过一段时间无法回答“这份备份到底验过没有”。建议至少记录:
- 备份标识(目录名或唯一 ID)。
- 校验时间与执行者(人或流水线)。
- 使用的选项(是否跳过校验和、格式、是否指定
-w)。 - 结论与耗时。
- 失败时的完整错误输出。
把这些记录与备份元数据放在一起,能在真正需要恢复时快速判断“该用哪一份、它是否被验证过”。
校验的频次设计
频次设计本质上是在“发现问题的及时性”与“资源消耗”之间取平衡:
- 每次备份后:跑快速检查(
--skip-checksums),成本低,能抓住传输与文件数量层面的问题。 - 每周或每次全量后:跑完整校验,能抓住内容级损坏。
- 每季度或按合规要求:做一次实际试恢复,验证端到端可用性。
这个三层结构的好处是:把大部分低级错误挡在最便宜的那一层。
校验失败时的重试逻辑
自动化流水线中,校验失败后是否重试需要谨慎设计:
- 若失败原因是“文件缺失”或“校验和不匹配”,重试通常无用——这些是确定性错误,重试只会重复消耗 I/O。
- 若失败原因是“网络存储瞬时不可用”“清单所在共享目录挂载失败”,重试可能是合理的。
因此更稳妥的做法是:区分错误类型,对“环境类”错误有限重试,对“内容类”错误直接告警并停止后续依赖步骤。
校验与权限、用户
pg_verifybackup 是一个客户端工具,它以当前操作系统用户的身份读取备份目录中的文件。因此:
- 执行校验的用户必须对备份目录有读权限。
- 校验过程不会连接数据库,不需要数据库账号,也不需要
REPLICATION权限。 - 校验本身不写任何文件(除标准输出外),因此不会破坏备份。
这一特点使它可以安全地在只读的归档存储上执行,也便于放在与数据库实例隔离的机器上运行——这在“校验机与生产机分离”的合规场景下很有用。
与校验和(data checksums)的关系
需要注意区分三种“校验和”:
- 数据页校验和:由实例初始化时的 data checksums 决定,
pg_checksums工具操作它,用于发现数据页静默损坏。 - 清单文件校验和:清单中每个文件记录的
Checksum字段,由制作备份时的选项决定。 - 清单自身校验和:
Manifest-Checksum,固定 SHA-256,用于保护清单不被篡改。
这三者服务的层次不同:第一层在实例内部,第二层在备份与内容之间,第三层在清单自身。理解这一点可以避免把“校验和”当成一个笼统的概念。
校验时的并发与 I/O 影响
pg_verifybackup 会顺序读取备份文件,是单进程的 I/O 密集任务。如果备份存放在与在线实例共享的存储(例如同一套 SAN、同一块网络盘)上,完整校验可能挤占实例的 I/O 带宽,间接影响业务。
因此建议:
- 完整校验尽量安排在业务低谷期。
- 若备份存放在独立存储上,可以在任意时间执行。
- 用
--skip-checksums做高频检查以降低平均负载。
校验通过后的下一步
校验通过不代表工作结束。一个完整的“备份可信”链路还包含:
- 校验通过(本页主题)。
- 恢复演练通过(能起库、数据正确)。
- 记录与归档(留存证据)。
后面两件事在本章后续的“恢复演练”一节会展开。这里先记住:pg_verifybackup 是这条链路的第一道自动化门槛,而不是终点。
在备份流水线中放在哪一步
一个合理的流水线顺序是:
pg_basebackup制作备份(生成清单)。- 把备份与清单一起传输到目标位置(两者必须一起搬,不能分开丢失)。
- 在目标位置立刻跑一次
pg_verifybackup --skip-checksums快速检查,确认传输没丢文件。 - 稍后(例如夜间空闲时段)跑一次完整校验。
- 定期做试恢复演练。
这个顺序的价值在于:快速检查能在传输后立刻发现“文件数量不对”这类低级错误,而完整校验消耗的 I/O 可以安排在非高峰时段。
传输清单时的注意事项
清单与备份是一体的。如果清单在传输中被截断,或者被放到了错误的位置,校验会以“清单损坏 / 系统标识符不匹配”的形式失败——这时需要先排除“传输问题”,而不是直接怀疑备份本身出了存储故障。
建议把清单与备份放在同一个目录、同一个归档包里传输,并记录它们的内容摘要,方便事后追溯。
实战示例
示例一:制作备份并立即校验
pg_basebackup -h mydbserver -D /var/lib/pgsql/backup/20260920
pg_verifybackup /var/lib/pgsql/backup/20260920这是最简洁的验证路径。若输出为空且退出码为 0,说明校验通过。
示例二:把清单移到备份目录之外再校验
pg_basebackup -h mydbserver -D /var/lib/pgsql/backup/backup1234
mv /var/lib/pgsql/backup/backup1234/backup_manifest /my/secure/location/backup_manifest.1234
pg_verifybackup -m /my/secure/location/backup_manifest.1234 /var/lib/pgsql/backup/backup1234这种方式适用于希望把清单单独做访问控制的场景。
示例三:忽略手工加入的文件并跳过校验和
pg_basebackup -h mydbserver -D /var/lib/pgsql/backup/data
# 运维在备份目录里放了一份说明文件
vim /var/lib/pgsql/backup/data/note.to.self
pg_verifybackup --ignore=note.to.self --skip-checksums /var/lib/pgsql/backup/data注意路径是相对备份根目录的 note.to.self。
示例四:tar 备份的校验
pg_verifybackup -n -F tar /var/lib/pgsql/backup/20260920_tar因为 tar 格式下 WAL 校验不受支持,显式加 -n 是必要的。
示例五:校验失败时的完整问题清单
pg_verifybackup /var/lib/pgsql/backup/20260920pg_verifybackup: error: could not open file "base/16384/24576": No such file or directory
pg_verifybackup: error: "base/16384/24580" has size 8192 on disk but size 65536 in the manifest
pg_verifybackup: error: checksum mismatch for file "base/16384/24584"不加 -e 时,三类问题一次全部报出,便于判断损坏范围。下面这份用 -e 则只会报第一行:
pg_verifybackup -e /var/lib/pgsql/backup/20260920示例六:把校验接入 CI 或定时任务
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/var/lib/pgsql/backup/$(date +%Y%m%d)"
if pg_verifybackup -q --skip-checksums "$BACKUP_DIR"; then
echo "quick check ok: $BACKUP_DIR"
else
echo "quick check FAILED: $BACKUP_DIR" >&2
exit 1
fi先用快速档位筛掉低级错误,再另安排完整校验。
示例七:从独立 WAL 目录校验
pg_verifybackup -w /mnt/wal_archive /var/lib/pgsql/backup/20260920当备份目录里没有 WAL、而归档在别处时使用。
示例八:查看当前清单的版本与字段
head -n 1 /var/lib/pgsql/backup/20260920/backup_manifest{ "PostgreSQL-Backup-Manifest-Version": 2, "System-Identifier": 7412345678901234567, "Files": [若版本为 2,则应当能在这个 JSON 中看到 System-Identifier 字段。
示例九:同时校验多份备份
for d in /var/lib/pgsql/backup/*/; do
if pg_verifybackup -q --skip-checksums "$d" >/dev/null 2>&1; then
echo "OK $d"
else
echo "FAIL $d"
fi
done适合做每日备份巡检的汇总。
示例十:配合试恢复的完整验证
# 1) 校验备份
pg_verifybackup -e /var/lib/pgsql/backup/20260920
# 2) 准备一个空的数据目录用于试恢复
install -d -m 0700 /var/lib/pgsql/testrestore
# 3) 复制备份内容
cp -a /var/lib/pgsql/backup/20260920/. /var/lib/pgsql/testrestore/
# 4) 配置恢复并启动(示例,需按环境调整)
cat >> /var/lib/pgsql/testrestore/postgresql.conf <<'EOF'
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-09-20 10:30:00+08'
recovery_target_action = 'promote'
EOF
touch /var/lib/pgsql/testrestore/recovery.signal这一步说明校验与试恢复是互补的:校验快但覆盖有限,试恢复慢但最接近真实。
注意事项
pg_verifybackup是 PostgreSQL 13 新增的,在更早版本上不存在这个工具,不要将其写进老版本的运维手册。- 没有
-c选项。-c/--manifest-checksums属于pg_basebackup,是制作备份时的选项,不要混淆。 - 每次校验都需要完整读取备份文件,是 I/O 密集型操作。大备份请安排在非高峰时段。
--progress与--quiet互斥,脚本中不要同时传这两个选项。--ignore的路径是相对路径,不是绝对路径;传绝对路径会被当作不匹配而无效。- tar 格式不支持 WAL 校验,需加
-n;只有 plain 格式才能做完整的四阶段校验。 - WAL 校验是版本相关的,必须用与被检查备份对应版本的
pg_verifybackup/pg_waldump。 - 校验通过不等于备份可用。配置正确性、数据业务正确性都需要试恢复来确认。
- 清单与备份必须一起传输与保存,不要把清单落到别处却又忘记它的位置。
Last-Modified字段不参与校验,不要指望它能发现“文件被替换成同大小、同内容”的异常。- 不要试图修复校验失败的文件。内容级损坏应当重做备份。
- 清单版本 1 没有
System-Identifier,自研解析工具需同时兼容两个版本。
最佳实践
- 把
pg_verifybackup --skip-checksums加进“备份完成后的即时检查”,第一时间发现文件数量与大小异常。 - 对每份全量备份安排一次完整校验(不跳过校验和),并记录校验结果与耗时。
- 在自动化流水线中使用
-e以尽快失败;人工排障时不加-e以拿到完整问题清单。 - 把清单与备份作为一个整体打包传输与归档,避免清单与备份配对错误。
- 备份制作时统一选择校验算法并写入运维规范,避免同一套体系里算法混杂导致运维认知负担。
- 对校验结果建立可追溯记录(备份标识、校验时间、结果、耗时),便于证明“备份曾被验证”。
- 校验通过后仍要按计划做试恢复演练,把“校验”与“演练”当作两道独立的门槛。
pg_wal与备份分离部署时,校验时使用-w指向归档目录,避免在备份目录中找不到 WAL 而失败。- 对 tar 备份固定使用
-n -F tar,并把这条写成脚本模板,避免每次手输遗漏。 - 把
pg_checksums(面向在线实例数据页)与pg_verifybackup(面向备份副本)分别纳入不同的巡检项,明确各自职责。 - 对于超过一定规模的备份,采用“快速模式高频跑、完整模式低频跑”的分层校验策略。
- 校验失败一律按“先排查清单配对与传输完整性,再判断内容损坏”的顺序处理,避免误判。
下一节
继续学习:备份策略设计
参考链接
- PostgreSQL 官方文档:pg_verifybackup
- PostgreSQL 官方文档:Backup Manifest Format
- PostgreSQL 官方文档:Backup Manifest Top-level Object
- PostgreSQL 官方文档:Backup Manifest File Object
- PostgreSQL 官方文档:Backup Manifest WAL Range Object
- PostgreSQL 官方文档:pg_basebackup
- PostgreSQL 官方文档:pg_checksums
- PostgreSQL 官方文档:Continuous Archiving and Point-in-Time Recovery
- PostgreSQL 官方文档:pg_waldump