4. 基础备份与pg_basebackup
在 PostgreSQL 的高可用体系中,基础备份(Base Backup)是流复制的起点。它把主库在某个时刻的整个数据目录复制出来,再配合 WAL 归档或流复制,就能把备库推进到与主库一致的状态。理解基础备份的关键,不是“复制文件”这个动作本身,而是它如何保证备份期间数据库的一致性。
一致性备份原理
PostgreSQL 的数据文件在运行中始终处于被修改的状态,直接复制数据目录会得到“撕裂”的页面和互相矛盾的元组。为此,PostgreSQL 采用“在线备份”机制:备份开始时记录一个起始 WAL 位置(Start LSN),备份结束时记录结束 WAL 位置(Stop LSN),并在这段时间内保证所有被修改的数据块在 WAL 中都有完整记录。恢复时,先还原数据目录,再重放从 Start LSN 到 Stop LSN 的 WAL,就能把数据文件“补齐”到一致状态。
pg_basebackup 正是这一机制的命令行实现。它通过复制协议连接主库,触发一次在线备份,把数据目录打包传输到本地或远端。备份过程中,主库会进入备份模式(或使用复制槽),确保 WAL 不被过早回收。因此,pg_basebackup 得到的备份天然包含恢复所需的一致性信息,只要 WAL 完整,就能恢复出一个可用的实例。
pg_basebackup 参数详解
pg_basebackup 的参数决定了备份的形态、传输方式和恢复便利性。以下是最常用的一组参数及其工程含义:
| 参数 | 含义 | 工程建议 |
|---|---|---|
| -D, --pgdata | 备份输出目录 | 必须为空目录;备库场景直接指向 $PGDATA |
| -h, --host | 主库主机名或 IP | 使用可解析的主机名,便于切换 |
| -p, --port | 主库端口 | 默认 5432,多实例时显式指定 |
| -U, --username | 连接用户 | 需具备 REPLICATION 或 SUPERUSER 权限 |
| -F, --format | 输出格式:plain / tar | 备库直连用 plain;归档传输用 tar |
| -X, --wal-method | WAL 包含方式:none / fetch / stream | 推荐 stream,边备份边传 WAL |
| -P, --progress | 显示进度 | 大库备份时观察进度,便于排障 |
| -R, --write-recovery-conf | 自动生成 standby.signal 和 primary_conninfo | 备库场景强烈建议开启 |
| -S, --slot | 使用复制槽 | 避免 WAL 被过早回收,需主库预先创建 |
| -c, --checkpoint | 检查点模式:fast / spread | fast 立即触发检查点,缩短备份窗口 |
其中 -X stream 与 -R 的组合最值得关注。-X stream 会在备份数据文件的同时,通过第二个连接实时传输 WAL,避免备份结束后还要单独去主库拉取 WAL;-R 则自动在目标目录写入 standby.signal 和 primary_conninfo,让备库启动后直接进入流复制状态,省去手工配置。
备份到备库的完整操作流程
下面以“主库 192.168.1.10:5432,备库 192.168.1.11,数据目录 /var/lib/pgsql/15/data”为例,演示一次完整的备库搭建。以下参数与路径均为教学示例,实际执行时请按环境调整。
第一步:主库准备复制用户与复制槽。复制用户需要具备 REPLICATION 权限;复制槽用于保证备份期间及后续流复制的 WAL 不被回收。
-- 在主库执行
CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'Repl@123';
SELECT * FROM pg_create_physical_replication_slot('standby_slot');
第二步:确认主库允许复制连接。检查 pg_hba.conf 中是否有针对备库 IP 的 replication 条目,并确认 listen_addresses 与 wal_level 满足要求(wal_level = replica 或更高)。
# pg_hba.conf 示例
host replication repl_user 192.168.1.11/32 scram-sha-256
# postgresql.conf 关键项
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
第三步:在备库执行 pg_basebackup。先停止备库实例,清空目标数据目录,再执行备份命令。注意 -D 指向的目录必须为空或不存在。
# 在备库执行
systemctl stop postgresql-15
rm -rf /var/lib/pgsql/15/data/*
chown postgres:postgres /var/lib/pgsql/15/data
pg_basebackup \
-h 192.168.1.10 \
-p 5432 \
-U repl_user \
-D /var/lib/pgsql/15/data \
-F plain \
-X stream \
-S standby_slot \
-P \
-R \
-c fast
执行过程中,-P 会输出类似 12345/67890 kB (12%) 的进度信息;-X stream 会同时传输 WAL;-R 会在数据目录生成 standby.signal 和 postgresql.auto.conf 中的 primary_conninfo。
第四步:启动备库并验证。启动备库后,通过 pg_stat_replication 和 pg_last_wal_receive_lsn() 观察复制状态。
# 启动备库
systemctl start postgresql-15
# 在主库查看复制状态
SELECT client_addr, state, sync_state, sent_lsn, replay_lsn
FROM pg_stat_replication;
# 在备库确认只读与接收位置
SELECT pg_is_in_recovery();
SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();
若 state 显示 streaming,且 replay_lsn 持续追赶 sent_lsn,说明备库已进入正常流复制状态。
常见错误与处理
错误 1:pg_basebackup: error: could not connect to server。通常是 pg_hba.conf 未放行备库 IP,或主库 listen_addresses 未监听对应地址。处理:检查主库 pg_hba.conf 的 replication 条目,确认 listen_addresses 包含备库可达的地址,并重载配置。
错误 2:FATAL: no pg_hba.conf entry for replication connection。复制连接走的是 replication 关键字,不是普通 database 条目。处理:在 pg_hba.conf 中显式添加 host replication repl_user 备库IP/32 scram-sha-256。
错误 3:ERROR: replication slot "standby_slot" does not exist。复制槽未创建或名称拼写错误。处理:在主库执行 SELECT * FROM pg_create_physical_replication_slot('standby_slot');,并确认 -S 参数与槽名一致。
错误 4:pg_basebackup: directory "/var/lib/pgsql/15/data" exists but is not empty。目标目录非空。处理:停止备库,清空目录后再执行;切勿在运行中的实例目录上直接覆盖。
错误 5:备份完成后备库无法启动,日志提示 could not find WAL segment。通常是 -X 使用了 none 或 fetch 但 WAL 未完整保留。处理:改用 -X stream 并配合复制槽,确保备份期间 WAL 不丢失。
排障时优先看三处:主库 pg_hba.conf 是否放行 replication、复制槽是否存在、备库数据目录是否为空。这三项覆盖了绝大多数 pg_basebackup 失败场景。
掌握 pg_basebackup 的一致性原理与参数组合后,备库搭建就从“手工拷贝 + 反复试错”变成了可重复、可验证的标准操作。下一步只需把复制槽、连接信息和监控指标固化到部署脚本中,就能稳定地批量扩展备库。