增量备份(pgBackRest / Barman)
pg_basebackup 解决的是「怎么拿到一份一致的完整备份」。但在生产环境里,每天都做一次全量备份往往是不现实的:TB 级数据库的全量备份要占用数小时的时间窗口、数倍于数据量的存储空间,以及对源库持续的 I/O 压力。真正可行的策略是「全量 + 增量」——每周(或每天)做一次全量,其余时间只备份「自上次备份以来发生变化的部分」。
增量备份的实现有两条完全不同的技术路线。第一条是 PostgreSQL 原生路线:PG17 引入了原生的块级增量备份能力,服务端通过 WAL 摘要(WAL summarization) 判断哪些数据块被修改过,客户端用 pg_basebackup --incremental 只拉取变更块,恢复前再用 pg_combinebackup 把「全量 + 一串增量」合并成完整备份。这条路线无需第三方软件,但功能相对朴素,没有保留策略、没有并行、没有加密、没有异地仓库管理。
第二条是 第三方备份工具路线:pgBackRest 与 Barman 是这个领域最主流的两个开源方案。它们把「备份链管理、保留策略(retention)、并行压缩、加密、远程仓库、WAL 归档、PITR 编排、监控与校验」打包成一整套流程,是生产环境的事实标准。其中 pgBackRest 采用自研的增量机制(文件级 / v2.46 起的块级增量),Barman 则区分「file-level 增量(rsync)」与「block-level 增量(基于 PG17 原生能力)」。
本页先讲清三种「增量」的语义差异与备份链概念,再分别展开 pgBackRest 与 Barman 的配置模型、备份类型、保留策略、增量机制与恢复方式。所有命令与配置项均来自两个工具的官方文档。
前置知识
建议先阅读:pg_basebackup、物理备份原理
基础概念
为什么需要增量备份
全量备份的成本随数据量线性增长。一个 2TB 的集簇,即使备份速度为 300MB/s,一次全量也要约两小时;如果每天做一次,保留 30 天,光备份存储就需要数十 TB。而业务数据的日均变更量可能只有几 GB——全量备份中 99% 的字节是重复的。
增量备份的价值就在于消除这些重复:
| 目标 | 增量备份如何实现 |
|---|---|
| 缩短备份窗口 | 只传输变更部分,备份耗时从「小时级」降到「分钟级」 |
| 降低存储占用 | 一份全量 + 若干增量,总量远小于 N 份全量 |
| 提高备份频率 | 备份变轻之后,可以从「每天一次」提高到「每小时一次」,缩小 RPO |
| 降低源库压力 | 读取的数据量更少,对在线业务 I/O 的挤占更小 |
代价是复杂度上升:增量备份不再是「自包含」的,它依赖一条备份链。链上任何一环损坏或丢失,链尾的增量就不可用。因此使用增量备份,本质上是在用「恢复复杂度」换「备份成本」。
三种「增量」的语义差异
中文里都叫「增量」,但 Full / Differential / Incremental 三者的含义有严格区别。pgBackRest 官方文档给出的定义最清晰:
| 类型 | 英文 | 备份内容 | 恢复依赖 |
|---|---|---|---|
| 全量 | Full Backup | 整个集簇的全部文件 | 自包含,不依赖任何其他备份 |
| 差异 | Differential Backup | 自上一次全量以来发生变化的文件 | 依赖那一次全量 |
| 增量 | Incremental Backup | 自上一次任意类型备份以来变化的文件 | 依赖上一次备份,以及它背后整条链 |
关键区别在「参照点」:
- Differential(差异) 的参照点永远是最近一次 Full。周一全量、周二差异、周三差异——周三的差异备份只包含「周一以来」的变化,周三这次不包含周二那次的内容。
- Incremental(增量) 的参照点是上一次备份(可以是全量、差异或另一个增量)。周一全量、周二增量、周三增量——周三的增量只包含「周二以来」的变化,体积最小。
用一张时间线看差异:
周一 Full ──┬── 周二 Diff(相对于周一)
└── 周三 Diff(相对于周一,不是相对于周二)
周一 Full ──┬── 周二 Incr(相对于周一)
└── 周三 Incr(相对于周二)因此:
- 恢复差异备份:只需要「最近一次差异 + 它对应的全量」,共 2 份。
- 恢复增量备份:需要「全量 + 从全量到目标之间的全部增量」,可能有很多份。
差异备份 = 更大的体积、更短的恢复链;增量备份 = 更小的体积、更长的恢复链。 实践中常见的组合是「每周全量 + 每天差异 + 每小时增量」,用差异备份在恢复链长度和存储占用之间取得平衡。
备份链与依赖关系
引入增量之后,「一个备份」不再是独立文件,而是链上的一个节点:
Full_20260927 ──→ Incr_20260928 ──→ Incr_20260929 ──→ Incr_20260930
│ │ │ │
必须存在 依赖前者 依赖前者 依赖前者由此产生几条铁律:
- 删除链中间的备份会让链尾全部失效。 删掉
Incr_20260928,那么Incr_20260929与Incr_20260930都无法恢复。 - 保留策略必须「从链尾往回删」,且不能删成断链。 这就是为什么 pgBackRest 的保留策略以 Full / Diff 为单位计数,而不是以任意备份为单位。
- 恢复时必须从链头(Full)开始。 工具会自动解析依赖,但前提是链上每个节点都还在、都通过校验。
PG17 原生增量备份的机制
PG17 的原生增量备份不比较文件修改时间,而是比较数据块。它的判断依据是 WAL 摘要(WAL summarization):
- 当
summarize_wal = on时,服务端会在后台生成 WAL 摘要文件,记录「WAL 中各个区段(区间)实际修改了哪些数据块」; - 做增量备份时,服务端根据「参考备份对应的 manifest 中记录的 LSN」到「本次备份起始 LSN」之间的 WAL 摘要,推导出需要备份的块;
- 客户端
pg_basebackup -i <old_manifest>只拉取这些块; - 由于增量备份只包含「部分块」,它不能直接启动,必须先由
pg_combinebackup与依赖的完整备份合并,产出 synthetic full backup(合成全量备份)。
要点:
| 事实 | 说明 |
|---|---|
summarize_wal 必须开启 | 未启用 WAL 摘要时无法执行增量备份 |
| 开启位置 | 只能在配置文件中设置(不是 ALTER SYSTEM 之外的普通参数),主库或备库均可 |
| 参考物 | 一份参考备份的 backup_manifest 文件 |
| 合并工具 | pg_combinebackup,参数为从最旧到最新的全部备份目录 |
| 合并产物 | synthetic full backup,可再作为后续增量备份的输入 |
增量备份与 WAL 归档是两回事
原生增量备份解决的是「基础备份怎么变小」,不解决「如何恢复到某个历史时刻」。PITR 依然需要连续的 WAL 归档;增量备份只是让「起点」的获取成本更低。两者必须同时配置。
pgBackRest 与 Barman 的定位差异
| 维度 | pgBackRest | Barman |
|---|---|---|
| 定位 | 备份/恢复工具(含 WAL 归档与 PITR 编排) | 备份管理器(backup manager,更强的灾备编排) |
| 增量机制 | 文件级增量;v2.46 起支持块级增量(block incremental) | file-level(rsync);block-level(依赖 PG17 原生能力) |
| 备份类型 | Full / Diff / Incr 三级 | Full + 两种 Incremental(无独立 Diff 概念) |
| 配置模型 | 配置文件 + stanza | 配置文件 + server(按服务器名组织) |
| 元数据 | 仓库内的备份信息 | 通过 barman check / show-backup 等命令查询 |
| 云对象存储 | 原生支持 S3 / Azure / GCS,且支持 SFTP | 通过 barman-cloud-* 系列工具支持 |
| 强项 | 性能(并行 + 块级增量)、压缩、加密、增量体积小 | 可观测性、保留策略编排、异地冗余、灾备流程 |
两者不是互斥的:有些团队用 Barman 做灾备编排,用 pgBackRest 做高效备份。选型时优先看「恢复链的可管理性」与「团队已有运维习惯」,而不是单看备份速度。
关键术语表
| 术语 | 出处 | 含义 |
|---|---|---|
| stanza(节) | pgBackRest | 一个 PostgreSQL 集簇的备份配置单元,定义了「数据在哪、备份到哪、怎么归档」 |
| repository(仓库) | pgBackRest | 存放备份与 WAL 归档的位置,可以是本地目录、专用仓库主机或对象存储 |
| retention(保留策略) | 两者 | 规定保留多少份全量/差异备份,超出的自动过期(expire) |
| backup chain(备份链) | 两者 | 一个全量及其派生出的全部增量/差异备份 |
| file-level incremental | Barman | 基于 rsync(+硬链接)的文件级增量,自包含 |
| block-level incremental | Barman / PG17 | 基于 pg_basebackup 与 WAL 摘要的块级增量,依赖备份链 |
--type | pgBackRest | backup 命令的备份类型:full / diff / incr |
backup_method | Barman | 备份方式:rsync 或 postgres(流式) |
语法与用法
原生路线:pg_basebackup + pg_combinebackup
# 0) 服务端必须先开启 WAL 摘要(写入 postgresql.conf 后重启/重载)
# summarize_wal = on
# 1) 周日:全量(产生 backup_manifest,作为后续增量的参考)
pg_basebackup -D /backup/full_20260928 -Fp -Xs -P
# 2) 周一:块级增量,参考全量的 manifest
pg_basebackup -D /backup/incr_20260929 -Fp -Xs -P \
-i /backup/full_20260928/backup_manifest
# 3) 需要恢复时:按「从最旧到最新」的顺序合并
pg_combinebackup /backup/full_20260928 \
/backup/incr_20260929 \
-o /backup/combined_20260929pgBackRest:命令行基本形态
pgbackrest [options] [command]# 创建 stanza、检查配置、执行三种类型的备份
pgbackrest --stanza=demo stanza-create
pgbackrest --stanza=demo check
pgbackrest --stanza=demo --type=full backup
pgbackrest --stanza=demo --type=diff backup
pgbackrest --stanza=demo --type=incr backup
# 查看备份信息、按保留策略清理过期备份
pgbackrest --stanza=demo info
pgbackrest --stanza=demo expireBarman:命令行基本形态
barman backup [OPTIONS] SERVER_NAME
barman restore [OPTIONS] SERVER_NAME BACKUP_ID DESTINATION_PATH# 全量备份、查看备份、校验配置
barman backup pg
barman list-backups pg
barman show-backup pg latest
barman check pg详细说明
pgBackRest 的配置模型:配置文件与 stanza
pgBackRest 的默认配置文件是 /etc/pgbackrest/pgbackrest.conf,配置格式是「类 INI」的:
- 段落(section)用方括号表示,如
[global]、[demo]; - 键值对形如
key=value; - 以
#开头的行是注释; - 不支持行尾注释,也不支持引号,键与值两端的空白会被去掉;
- 同名段落出现多次时会合并。
[global] 段放全局设置(仓库路径、保留策略、加密、日志级别等),其余段落名就是 stanza 名,用于标识「哪个集簇」。
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
repo1-retention-diff=7
repo1-cipher-type=aes-256-cbc
compress-type=zstd
process-max=4
log-level-console=info
[demo]
pg1-path=/var/lib/postgresql/18/demo
pg1-socket-path=/var/run/postgresql关于 stanza 命名,官方文档给了一条很实用的建议:不要用 main / prod 这类「本机集簇名」,而要用描述用途的名字(如 app、dw)。因为同一个 stanza 名会同时用于主库和所有副本,用功能名可以避免「主备切换后配置指向错乱」。
pg1-path 必须与 PostgreSQL 实际报告的 data_directory 完全一致,否则备份会直接报错——这是 pgBackRest 的强校验之一。原因也很直接:恢复场景下数据库进程可能不可用,pgBackRest 无法向 PostgreSQL 询问路径,只能依赖配置。
配置的加载方式有几种(官方文档列出的组合):
默认(不传任何选项) → 加载默认配置文件 + 默认 include 目录下的 *.conf
--config=<文件> → 只加载指定文件(必须存在)
--config-include-path=<目录> → 加载该目录下全部 *.conf
--config-path=<目录> → 覆盖默认配置文件与 include 目录的基础路径pgBackRest 的三级备份与备份链
pgBackRest 的 backup 命令通过 --type 指定备份类型,取值 full / diff / incr,缺省即 incr。这是一个容易踩坑的默认值:只敲 pgbackrest backup 不会做全量。
三种类型的行为:
# 全量:整个集簇,第一个备份必须是 full
pgbackrest --stanza=demo --type=full backup
# 差异:自上一次 full 以来变化的文件
pgbackrest --stanza=demo --type=diff backup
# 增量:自上一次任意类型备份以来变化的文件(默认)
pgbackrest --stanza=demo --type=incr backup依赖关系(官方文档明确说明):
- Full 是自包含的,总是可以直接恢复,不依赖 full 之外的任何文件;
- Diff 恢复时需要「该 diff + 它对应的上一次 full」都有效;
- Incr 恢复时需要「该 incr + 它之前所有 incr + 之前的 diff(若有)+ 之前的 full」全部有效;如果不存在 diff,则需要「该 incr 之前所有 incr + full」全部有效。
用 info 可以看到备份链与其依赖是否完整:
pgbackrest --stanza=demo infostanza: demo
status: ok
cipher: aes-256-cbc
db (current)
wal archive min/max (18): 000000010000000000000002/00000001000000000000000F
full backup: 20260927-020011F
...
diff backup: 20260929-020014D
...
incr backup: 20260930-020017I
...备份标识形如 20260927-020011F:时间戳 + 类型后缀(F = full、D = diff、I = incr)。info 命令也可以用 --set=<备份标识> 查看单个备份的详细信息,或用 --output=json 得到便于监控解析的 JSON。
info 的 status: ok 依赖仓库中的元数据,不需要连接(甚至不需要启动)PostgreSQL——这正是「恢复场景下配置必须自包含」的设计动机。
pgBackRest 的保留策略
保留策略决定「保留多少份备份」,由 expire 命令执行(backup 命令也会在完成后自动触发过期处理)。
| 配置项 | 含义 |
|---|---|
repo1-retention-full | 保留多少份 full 备份 |
repo1-retention-diff | 保留多少份 diff 备份 |
repo1-retention-archive-type | 归档保留的计数依据:full / diff / incr |
repo1-retention-archive | 保留多少个「按上项计数」的备份所对应的 WAL 归档 |
[global]
repo1-retention-full=2
repo1-retention-diff=7
repo1-retention-archive-type=full
repo1-retention-archive=2两条关键规则:
- 删除以「链」为单位。 保留策略不会被满足到「把链删断」——如果删掉某个 full 会让某个增量失去依赖,pgBackRest 不会这样删。
- WAL 归档的保留与备份保留绑定。
repo1-retention-archive控制「保留多少个备份所覆盖的 WAL」,设置不当会导致 PITR 时 WAL 已被清理。
手工触发过期(也可用 --dry-run 预览):
pgbackrest --stanza=demo expire
pgbackrest --stanza=demo --dry-run expirepgBackRest 的压缩、加密与并行
压缩由 compress-type 控制,它同时影响备份与 WAL 归档的压缩方式:
[global]
compress-type=zstd
compress-level=3加密在客户端完成(即使仓库本身是 S3 等支持服务端加密的对象存储,pgBackRest 也坚持客户端加密):
| 配置项 | 取值 | 说明 |
|---|---|---|
repo1-cipher-type | none(默认)、aes-256-cbc | 仓库加密算法 |
启用加密后需要提供口令(通常通过 repo1-cipher-pass 或环境变量提供),口令丢失意味着备份永久不可读,务必纳入密钥管理。
并行由 process-max 控制,它决定同时运行的压缩/传输进程数:
[global]
process-max=4其他与性能/可靠性相关的常用项:
| 配置项 | 作用 |
|---|---|
buffer-size | I/O 缓冲大小,默认 1MiB,允许 16KiB ~ 16MiB |
start-fast | 备份开始时立即强制一次检查点,让备份尽快启动 |
backup-standby | 允许从备库执行备份,减轻主库压力 |
spool-path | 异步归档时暂存 WAL 的目录 |
log-level-console | 控制台日志级别:off/error/warn/info/detail/debug/trace |
start-fast 与 Barman 的 immediate_checkpoint 是同一个思路:用一次「立即检查点」换取更短的备份启动延迟,代价是把检查点的 I/O 一次性压到磁盘上。对在线业务敏感的库要谨慎开启。
pgBackRest 的 Block Incremental(v2.46+)
pgBackRest 传统的增量是文件级的:判断一个数据文件是否变化,变化了就整文件拷贝。对于一张大表,即使只改了一行,该文件也会被整份传输。这在 VLDB 场景下依然低效。
v2.46(2023-05-22)引入了 Block Incremental Backup:不再以文件为单位,而是存储发生变化的数据块。它必须与 file bundling 配合使用:
| 配置项 | 引入版本 | 作用 |
|---|---|---|
repo1-bundle | v2.39 | 把多个小文件打包存储,减少仓库中的文件数量 |
repo1-block | v2.46 | 块级增量:只存储变化的块,而非整个文件 |
[global]
repo1-path=/var/lib/pgbackrest
repo1-bundle=y
repo1-block=y功能定位的差异(对比传统文件级增量):
文件级增量:文件 A(1GB)改了 1 行 → 备份整个文件 A(1GB)
块级增量 :文件 A(1GB)改了 1 行 → 备份变更的少数几个 8KB 块与 PG17 原生块级增量的关系
pgBackRest 的 block incremental 是自己实现的机制(基于仓库侧的块存储),不以 PG17 的 WAL 摘要为前提。它解决的是「仓库中重复块过多」的问题,可以与任意版本的 PostgreSQL 配合(受 pgBackRest 自身版本约束)。而 PG17 原生增量是「服务端识别变更块、客户端只拉变更块」,二者机制不同、可以叠加。
Barman 的架构与配置
Barman(Backup and Recovery Manager)的定位比 pgBackRest 更偏「备份管理」。它的模型是:一个 Barman 服务器,管理多个被备份的 PostgreSQL 服务器,每台 PostgreSQL 服务器在配置中有一个条目。
配置文件通常是 /etc/barman.conf(或 /etc/barman/barman.conf,再通过 barman.conf.d 分片):
[barman]
barman_user = barman
barman_home = /var/lib/barman
barman_lock_directory = /var/run/barman
log_file = /var/log/barman/barman.log
compression = gzip
[pg]
description = "Primary PostgreSQL server"
ssh_command = ssh postgres@pg
conninfo = host=pg user=barman dbname=postgres
backup_method = postgres
backup_compression = zstd
backup_compression_format = tar几条实务规则:
barman_lock_directory必须放在本地文件系统上(不要放 NFS)。- 若把备份放在 NFS 上:至少使用 NFSv4,并采用
hard,sync挂载。 - PG15 起不再支持 exclusive 备份,唯一方式是 concurrent backup;若
backup_options未设置,Barman 会自动设为concurrent_backup。 - 备份启动前 WAL 必须已正确归档到 Barman(通过
archiver或streaming_archiver),否则备份会失败。
带宽与压缩相关的配置项:
| 配置项 | 适用方法 | 说明 |
|---|---|---|
bandwidth_limit | rsync 与 postgres | 最大速率(KB/s),默认 0 表示不限速 |
tablespace_bandwidth_limit | 仅 rsync | 按表空间分别限速,格式 tbname:bwlimit[,...] |
network_compression | 不适用于 postgres | 是否压缩网络传输 |
backup_compression | 仅 postgres | 备份压缩算法:gzip / lz4 / zstd / none |
backup_compression_format | postgres | plain(解压后落盘)或 tar(压缩包,默认) |
backup_compression_location | postgres | server 或 client:压缩在哪一侧执行 |
backup_compression_workers | postgres + zstd | 压缩线程数(默认 0) |
immediate_checkpoint | 两者 | 是否立即执行检查点(默认 false) |
压缩备份的恢复前提
若使用 backup_compression,必须同时设置 staging_path 与 staging_location,否则压缩备份无法恢复。这是 Barman 文档明确要求的配套关系。
Barman 的 file-level 增量(rsync + reuse_backup)
Barman 的 file-level incremental 基于 rsync 与硬链接,因此要求操作系统与备份所在文件系统都支持这两者。其核心思想是:后续备份中未变化的文件直接复用上一份备份的文件(硬链接),从而既省空间又省时间。
开关是 reuse_backup(全局或按服务器):
| 取值 | 行为 |
|---|---|
off | 标准全量备份(默认) |
link | 复用上一份备份,未变化文件建硬链接(省空间也省时间) |
copy | 复用上一份备份,未变化文件做拷贝(省时间但不省空间) |
[pg]
backup_method = rsync
ssh_command = ssh postgres@pg
reuse_backup = link也可以在命令行临时覆盖:
barman backup --reuse-backup=link pgfile-level 增量的一个重要特性:它是自包含的。硬链接去重意味着「删除被复用的备份」不会破坏其他备份的完整性——共享的文件会保留到最后一个引用它的备份也被删除为止。因此不需要因为删除某份备份而重新做全量。
另外,对「第一次备份」设 reuse_backup = link 或 copy 没有任何效果:没有可链接/可复制的既有文件,它仍然是一次全量。
Barman 的 block-level 增量(PG17)
Barman 从 3.11 开始支持 block-level incremental backup,它建立在 PG17 的原生增量能力之上。与 file-level 的关键差异:
| 维度 | file-level | block-level |
|---|---|---|
| 传输层 | rsync over SSH | pg_basebackup 流式连接 |
| 前置要求 | 无(除文件系统支持硬链接) | PG17+、summarize_wal 已开启、backup_method=postgres |
| 去重粒度 | 文件 | 数据页(块) |
| 是否自包含 | 是(硬链接) | 否(依赖备份链) |
| 压缩支持 | 视 rsync 传输而定 | 目前不支持压缩备份 |
| 需要的配置 | reuse_backup | --incremental + 父备份 ID |
配置前提:
[pg]
backup_method = postgres命令形式为「--incremental + 一个父备份标识」:
barman backup --incremental BACKUP_ID SERVER_NAME父备份可以是 full 或另一个 incremental;也可以用 last-full / latest-full 这类快捷方式引用「最近一次符合条件的全量备份」。
两种增量互不兼容
Barman 文档明确:不同类型的增量备份不能混用。你不能在 rsync 备份之上做 block-level 增量,也不能在 pg_basebackup 创建的流式备份之上做 file-level 增量。另外,block-level 增量目前不支持压缩备份。切换增量类型时,必须先做一次对应的全量。
还有两条易被忽略的约束:
- 若在两次 block-level 增量之间开启了
data_checksums,建议重新做一次全量备份——校验和配置不一致可能在恢复时出问题。 summarize_wal必须在最初那份全量备份之前就已启用,否则后续增量无法进行。
Barman 的恢复:restore 与 delta-restore
新版 Barman 的恢复命令是:
barman restore [OPTIONS] SERVER_NAME BACKUP_ID DESTINATION_PATH早期的文档与脚本中使用的是 barman recover,它在较新版本中作为 barman restore 的别名继续可用——如果你的自动化脚本里还有 barman recover,建议统一迁移到 restore 以避免混淆。
BACKUP_ID 可以写具体备份标识,也可以用 auto 让 Barman 自行选择「满足恢复条件的最合适备份」:
# 恢复到目标目录
barman restore pg latest /var/lib/postgresql/18/main
# 由 Barman 自动选择备份
barman restore pg auto /var/lib/postgresql/18/maindelta-restore(增量恢复) 是一个大幅缩短恢复时间的特性:如果目标目录里已经有一份「接近目标状态」的数据(例如崩溃后的原数据目录,或已恢复到一半的目录),Barman 只回填差异部分,而不是整份重写。
| 配置/选项 | 说明 |
|---|---|
recovery_options='delta-restore' | 在配置中全局/按服务器启用 |
--delta-restore / --no-delta-restore | 命令行开关 |
recovery_options=get-wal,delta-restore | 多个恢复选项用逗号组合 |
delta-restore 的适用限制
delta-restore 只支持本地 plain 格式备份的恢复,或者 staging_location=local 时的远程恢复。如果你想利用它加速恢复,就不要把备份做成 tar 压缩包(那样必须先解压到 staging,再恢复)。
Barman 的云端与异地能力
Barman 把「对象存储上的备份」拆成一组独立工具(barman-cloud-*),它们可以脱离 Barman 服务器单独运行:
| 工具 | 作用 |
|---|---|
barman-cloud-backup | 把备份上传到对象存储 |
barman-cloud-restore | 从对象存储恢复备份 |
barman-cloud-wal-archive | 把 WAL 归档到对象存储 |
barman-cloud-wal-restore | 从对象存储取回 WAL |
barman-cloud-backup-list | 列出云端备份 |
barman-cloud-backup-show | 查看某个云端备份的详情 |
barman-cloud-backup-keep | 把某个云端备份标记为「不可自动删除」 |
barman-cloud-backup-delete | 删除云端备份 |
barman-cloud-check-wal-archive | 检查 WAL 归档状态 |
配合 WAL 归档使用的还有 barman-wal-archive 与 barman-wal-restore(来自 barman-cli 包)——它们把 WAL 归档/取回封装成可以直接写进 archive_command / restore_command 的单条命令。
「本地备份 + 对象存储副本」的组合(Barman 文档称之为 geographical redundancy,地理冗余)能在机房级故障时保住备份:本地用于快速恢复,云端用于灾难兜底。
备份加密与密钥管理
两个工具都支持客户端加密,且都把「口令/密钥」交给运维侧的密钥管理:
- pgBackRest:
repo1-cipher-type=aes-256-cbc,客户端加密,需要提供口令(repo1-cipher-pass或环境变量); - Barman:
encryption=gpg(目前仅gpg与none),依赖gpg2.1+ 与预先准备好的密钥对,用encryption_key_id指定公钥 ID。
加密口令丢失 = 备份永久不可用
加密是客户端行为,服务端与备份工具都无法帮你解密。把加密口令纳入密钥管理系统(KMS / 密码管理器 / 保险柜流程),并确保恢复演练时使用与生产相同的口令来源。切勿把口令明文写在配置文件里、或随备份一起拷贝。
实战示例
示例一:pgBackRest 从零到第一次全量
# 1) 准备目录
sudo mkdir -p /var/lib/pgbackrest /var/log/pgbackrest
sudo chown postgres:postgres /var/lib/pgbackrest /var/log/pgbackrest# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
process-max=4
[demo]
pg1-path=/var/lib/postgresql/18/demo# 2) 创建 stanza
sudo -u postgres pgbackrest --stanza=demo stanza-create
# 3) 检查配置(会验证 pg1-path、归档设置、仓库可写等)
sudo -u postgres pgbackrest --stanza=demo check
# 4) 第一次备份:必须是 full
sudo -u postgres pgbackrest --stanza=demo --type=full backupP00 INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
P00 INFO: backup command begin 2.59.1: --exec-id=12345 --log-level-console=warn --pg1-path=/var/lib/postgresql/18/demo ...
P00 INFO: backup start archive = 000000010000000000000005, lsn = 0/5000028
P00 INFO: new backup label = 20260930-020011F
P00 INFO: full backup size = 1200.5MB
P00 INFO: backup command end: completed successfully示例二:pgBackRest 的「周全量 + 日差异 + 小时增量」
# 周日全量
sudo -u postgres pgbackrest --stanza=demo --type=full backup
# 周一至周六:每天一次差异(相对最近一次全量)
sudo -u postgres pgbackrest --stanza=demo --type=diff backup
# 每小时的增量(相对上一次任意类型备份)
sudo -u postgres pgbackrest --stanza=demo --type=incr backup
# 查看当前备份链
sudo -u postgres pgbackrest --stanza=demo infostanza: demo
status: ok
db (current)
wal archive min/max (18): 000000010000000000000005/00000001000000000000002C
full backup: 20260927-020011F
timestamp start/stop: 2026-09-27 02:00:11+08 / 2026-09-27 02:21:37+08
wal start/stop: 000000010000000000000005 / 00000001000000000000000A
database size: 1200.5MB, backup size: 1200.5MB
diff backup: 20260929-020014D
wal start/stop: 00000001000000000000001C / 00000001000000000000001F
database size: 1200.5MB, backup size: 96.2MB
incr backup: 20260930-020017I
wal start/stop: 000000010000000000000028 / 00000001000000000000002C
database size: 1200.5MB, backup size: 104.7MB示例三:pgBackRest 配置 WAL 归档与 PITR 恢复
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
repo1-retention-archive-type=full
repo1-retention-archive=2# postgresql.conf 中让 PostgreSQL 调用 pgBackRest 归档 WAL
archive_mode = on
archive_command = 'pgbackrest --stanza=demo archive-push %p'# 恢复到某个时间点
sudo -u postgres pgbackrest --stanza=demo \
--type=time --target="2026-09-30 09:15:00+08" \
--target-action=promote \
restoreP00 INFO: restore command begin 2.59.1: --exec-id=23456 --stanza=demo --type=time --target="2026-09-30 09:15:00+08" --target-action=promote ...
P00 INFO: restore backup set 20260930-020017I
P00 INFO: write updated /var/lib/postgresql/18/demo/postgresql.auto.conf
P00 INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
P00 INFO: restore command end: completed successfully示例四:Barman 的流式(postgres 方法)备份与 block-level 增量
# /etc/barman.conf
[barman]
barman_home = /var/lib/barman
barman_lock_directory = /var/run/barman
log_file = /var/log/barman/barman.log
[pg]
description = "Primary PostgreSQL 18"
conninfo = host=pg user=barman dbname=postgres
ssh_command = ssh postgres@pg
backup_method = postgres
backup_compression = zstd
backup_compression_format = tar
staging_path = /var/lib/barman/staging
staging_location = local# 前提:PostgreSQL 端 summarize_wal = on(且早于第一次全量)
barman check pg
barman backup pg
# 基于最近一次全量做块级增量
barman backup --incremental latest-full pg
# 查看备份清单
barman list-backups pgpg 20260928T020011 - Mon Sep 28 02:21:37 2026 - Size: 1.2 GiB - Status: DONE
pg 20260930T020017 - Wed Sep 30 02:19:52 2026 - Size: 1.5 GiB - Status: DONE示例五:Barman 的 file-level 增量(rsync + 硬链接)
[pg]
backup_method = rsync
ssh_command = ssh postgres@pg
reuse_backup = link
bandwidth_limit = 51200
tablespace_bandwidth_limit = tbs_index:20480# 常规备份就会自动复用上一份(reuse_backup=link)
barman backup pg
# 临时切换策略:这次做「拷贝复用」而不是硬链接
barman backup --reuse-backup=copy pg示例六:Barman 恢复与 delta-restore 加速
# 1) 普通恢复:恢复到目标目录
barman restore pg latest /var/lib/postgresql/18/main
# 2) 目标目录已有接近的数据时,用 delta-restore 只回填差异
barman restore --delta-restore pg latest /var/lib/postgresql/18/main# 或在配置中全局启用
[pg]
recovery_options = get-wal,delta-restore注意事项
pgBackRest 的 backup 默认是 incr。 忘记写 --type=full 时不会得到全量备份,而且第一个备份必须显式指定 full。
链中间不能删。 手工删除仓库里的某个备份(而不是通过 expire)极可能造成断链,让链尾的增量全部失效。只通过 expire 与保留策略来淘汰备份。
WAL 归档保留与备份保留必须一起考虑。 repo1-retention-archive 设置过小会导致「备份还在,但它对应的 WAL 已被清理」,PITR 时就地重放失败。
pgBackRest 的本地与远端版本必须完全一致。 版本不匹配时 WAL 归档与备份都会停止工作,并报 ProtocolError 之类的协商错误;升级时要「一起升」。
别用 root 跑 pgBackRest。 默认只有 restore 命令允许以 root 运行(因为它要精细处理文件属主);其他命令以 root 运行会创建 root 属主的仓库文件,导致后续操作失败。
并发备份没有意义。 多数工具内部已经并行(process-max),再叠加多个备份进程只会同时压榨源库 I/O。
block-level 增量对配置变更敏感。 PG17 原生增量要求 summarize_wal 在第一次全量之前就已开启;Barman 的 block-level 增量还要求两次增量之间不要变更 data_checksums(变更了就该重做全量)。
Barman 的两种增量不可混用。 file-level 与 block-level 之间的父备份不能互相引用;切换类型必须重做全量。
压缩备份需要 staging 才能恢复。 Barman 使用 backup_compression 时必须配 staging_path 与 staging_location;delta-restore 也不适用于 tar 格式。
NFS 上有额外要求。 barman_lock_directory 必须在本地文件系统;NFS 至少 NFSv4,并用 hard,sync 挂载。Barman 官方也明确不推荐「本地备份到 NFS」作为主要方案。
加密口令必须纳入密钥管理。 丢了口令就等于丢了备份;不要把口令与备份放在同一个位置。
增量备份不能替代恢复演练。 备份链越长,恢复路径越复杂。定期做一次「从最旧全量 + 全部增量」的完整恢复演练,才能证明这条链真的可用。
保留策略要按 RPO/RTO 反推。 「保留 2 份全量」意味着最坏情况下你要接受「最近一次全量之后」的丢失窗口,除非有 WAL 归档把窗口压到很小。
最佳实践
先定 RPO/RTO,再定备份类型与频率。 RPO 决定「WAL 归档 + 增量备份」的频率下限,RTO 决定「保留多少全量、恢复链能有多长」。工具选型放在指标明确之后。
Full / Diff / Incr 三层组合,而不是只做 Full + Incr。 例如「周日 full、每日 diff、每小时 incr」:diff 把恢复链限制在「一份 full + 一份 diff」以内,incr 把备份窗口压到最小。
保留策略一律交给工具,手工删备份视为事故。 使用
pgbackrest expire/ Barman 的保留策略配置,绝不手工rm仓库文件;在删除前用--dry-run或list-backups确认。把备份校验做进流程。 pgBackRest 用
verify校验仓库内容,Barman 用check/show-backup确认状态;校验失败立即告警,不许坏备份进入保留期。
sudo -u postgres pgbackrest --stanza=demo verify
barman check pg用立即检查点换取可预测的备份窗口。 对时间窗口敏感的场景,开启 pgBackRest 的
start-fast或 Barman 的immediate_checkpoint;对在线 I/O 敏感的场景保持默认的摊薄式检查点。从备库做备份。 pgBackRest 用
backup-standby,Barman 把backup_method=postgres指向备库,可把备份的读取压力从主库移走;注意备库备份对full_page_writes等前提的要求。性能调优先调并行度,再调压缩级别。
process-max提高吞吐,压缩级别只影响 CPU 与体积的权衡;在 I/O 受限的环境中,适度降低压缩级别往往整体更快。有 VLDB 场景优先考虑块级增量。 pgBackRest 用
repo1-block=y(配合repo1-bundle=y),Barman 用--incremental;前者减少仓库重复块,后者减少网络传输量。仓库加密默认打开。 pgBackRest 用
repo1-cipher-type=aes-256-cbc,Barman 用encryption=gpg;口令走密钥管理系统,恢复演练验证口令可用。异地/云端必须有一份。 用 pgBackRest 的对象存储仓库,或 Barman 的
barman-cloud-backup把备份送出去;本地副本用于快恢复,异地副本用于灾难兜底。
barman-cloud-backup --cloud-provider aws-s3 s3://pg-backup/pg pg备份标识不可覆盖、命名可追溯。 让工具生成的时间戳标识(
20260930-020017I)保持原样,不要在仓库里做自定义重命名,否则元数据与实际内容会脱节。每季度做一次「最坏情况」恢复演练。 从最旧的可用全量开始,把整条链恢复到临时实例并用数据校验工具比对,把演练时长记录下来修正 RTO 估算。
下一节
继续学习:文件系统级备份(LVM / ZFS)
参考链接
- PostgreSQL 官方文档:Continuous Archiving and Point-in-Time Recovery (PITR)
- PostgreSQL 官方文档:Write Ahead Log(WAL Summarization / summarize_wal)
- PostgreSQL 官方文档:pg_basebackup
- PostgreSQL 官方文档:pg_combinebackup
- PostgreSQL 官方文档:pg_verifybackup
- PostgreSQL 官方文档:Release 17(原生增量备份)
- pgBackRest 官方文档:User Guide
- pgBackRest 官方文档:Configuration Reference
- pgBackRest 官方文档:Command Reference
- Barman 官方文档:Backups(增量备份与备份方法)