pg_dumpall 全集群备份
pg_dump 只能导出一个数据库,而一个 PostgreSQL 集群里除了业务库,还有一类「不属于任何单个数据库」的对象:角色(role)、表空间(tablespace)、以及配置参数的权限授予。这些对象被所有数据库共享,pg_dump 不会碰它们。集群级对象丢失的后果往往比丢一个业务库更麻烦——恢复脚本里满屏的 role "app_user" does not exist、tablespace "ssd" does not exist,最后不得不手工去比对原库的 pg_roles。
pg_dumpall 就是为解决这个问题而生的:它把整个集群导出成一个 SQL 脚本。实现方式是先导出全局对象,再对集群里的每一个数据库依次调用 pg_dump,把所有输出拼接成一份脚本。
理解这个实现方式非常关键,因为它直接决定了两条重要结论:第一,pg_dumpall 的输出只能是纯文本 SQL(多个数据库的导出无法塞进一个归档文件);第二,它是「逐库依次导出」的,因此不保证跨数据库的一致性——库 A 导出时刻的状态与库 B 可能相差几分钟。
前置知识
建议先阅读:pg_dump 基础用法、表空间
基础概念
pg_dumpall 与 pg_dump 的分工
| 维度 | pg_dump | pg_dumpall |
|---|---|---|
| 作用范围 | 单个数据库 | 整个集群 |
| 全局对象(角色 / 表空间 / 参数权限) | 不包含 | 包含 |
| 输出格式 | plain / custom / directory / tar | 仅 plain(纯文本 SQL) |
| 可并行 | 支持(-Fd -j) | 不支持 |
| 可选择性恢复 | 支持(pg_restore) | 只能整段执行 |
| 跨库一致性 | 不涉及 | 不保证 |
| 需要权限 | 表读权限即可 | 通常需要超级用户 |
| 密码认证 | 一次连接一次认证 | 每库一次连接,各认证一次 |
两者的关系不是替代而是互补:
pg_dumpall -g负责「集群骨架」:角色、表空间、参数权限;pg_dump -Fc负责「每个库的血肉」:定义与数据。
这也是生产环境推荐的组合策略,后文会展开。
全局对象到底包含什么
按官方定义,pg_dumpall 额外导出的全局对象有三类:
| 类别 | 对应 SQL | 说明 |
|---|---|---|
| 数据库角色 | CREATE ROLE / ALTER ROLE | 含成员关系、属性、默认密码 |
| 表空间 | CREATE TABLESPACE | 含 I/O 参数、位置路径 |
| 配置参数权限 | ALTER ROLE ... SET、GRANT SET ON PARAMETER | 角色级参数默认值与设置权限 |
| 数据库本身 | CREATE DATABASE | 每个库一条,含 owner / encoding / locale |
另外,pg_dumpall 的输出中会出现 \connect(psql 元命令),用于在脚本执行过程中切换到每个数据库。这是纯文本脚本特有的机制,归档格式没有等价物。
输出脚本的骨架
一份完整的 pg_dumpall 输出大致是下面的结构:
--
-- PostgreSQL database cluster dump
--
-- 1) 全局对象:角色
CREATE ROLE app_user;
ALTER ROLE app_user WITH LOGIN NOSUPERUSER ...;
ALTER ROLE app_user WITH PASSWORD 'SCRAM-SHA-256$4096:...';
-- 2) 全局对象:表空间
CREATE TABLESPACE ssd OWNER postgres LOCATION '/data/tblspc/ssd';
-- 3) 数据库定义
CREATE DATABASE orders WITH TEMPLATE = template0 ENCODING = 'UTF8';
ALTER DATABASE orders OWNER TO app_user;
-- 4) 切库并导出内容
\connect orders
-- ...此处是该库的 pg_dump 输出(定义 + 数据 + 权限)...
\connect analytics
-- ...下一个库...
-- 5) 收尾:参数权限等
-- PostgreSQL database cluster dump complete三个值得注意的细节:
- 角色密码默认会被导出,且是 SCRAM-SHA-256 校验子(salt + verifier),不是明文;
\connect依赖 psql,因此恢复必须用psql -f,不能用pg_restore;- 开头必须先连上某个库才能导全局对象,默认连
postgres,不存在则退到template1。
为什么不能保证跨库一致性
pg_dumpall 内部对每个库调用一次 pg_dump,每次调用是独立的连接、独立的快照。假设集群里有 10 个库,每个库导出耗时 5 分钟:
时间轴 →
库 A |==== 快照点 t0 ====|
库 B |==== 快照点 t5 ====|
库 C |==== 快照点 t10 ====|
...
库 J |==== 快照点 t45 ====|如果业务在库 A 和库 B 之间有跨库逻辑关联(比如 A 记订单、B 记库存),那么导出的两份数据可能对不上——A 里有一笔订单,B 里的库存扣减可能发生在 B 的快照之后而没被记录。
官方对此没有「一致性」承诺,文档中强调的是「导出整个集群的脚本」,而不是「一致地导出」。如果需要多库同一时刻的一致性,必须用 pg_export_snapshot() + pg_dump --snapshot 手工绑定,或者干脆改用物理备份。
逐库连接与认证
pg_dumpall 需要多次连接服务端(每个库一次,还要为全局对象连一次)。这带来两个实际影响:
- 密码认证会反复提示。用
-W时每个库都要输一次密码,几乎无法忍受;正确做法是配置~/.pgpass; - 连接次数多,成本不低。大集群(上百个库)执行
pg_dumpall会产生上百次连接,注意max_connections与连接开销。
密码敏感性
默认情况下,角色密码以 SCRAM-SHA-256 校验子的形式出现在脚本里:
ALTER ROLE app_user WITH PASSWORD 'SCRAM-SHA-256$4096:...salt...:...storedkey:serverkey...';它虽然不可逆,但足以用于离线暴力破解(尤其弱密码),因此这份脚本必须当作机密文件对待:权限设为 0600、不落公共目录、不进代码仓库。
如果目标是「只要结构不要密码」,用 --no-role-passwords:
pg_dumpall -g --no-role-passwords -f globals_nopass.sql该选项的行为有两个重要后果,官方文档写得很明确:
- 恢复后角色密码为 NULL,密码认证会一直失败,直到重新设置密码;
- 因为不需要密码,角色信息改为从视图
pg_roles读取(而不是pg_authid),因此在pg_authid访问受限的环境下也能用。
权限要求
导出时:pg_dumpall 要读取所有库的表,因此通常必须以超级用户身份连接才能导出完整内容。非超级用户在遇到无权限的库时会报错跳过。
恢复时:脚本里包含 CREATE ROLE 与 CREATE DATABASE,因此执行脚本的账号也必须有超级用户权限,否则会在第一批语句就失败。
关键术语
| 术语 | 含义 |
|---|---|
| 集群(cluster) | 一个 PostgreSQL 实例管理的数据目录及其下所有数据库 |
| 全局对象(global objects) | 角色、表空间、参数权限等跨库共享对象 |
\connect | psql 元命令,切换到指定数据库继续执行脚本 |
| 参数权限 | GRANT SET ON PARAMETER 授予的设置配置参数的能力 |
| SCRAM-SHA-256 | PostgreSQL 10+ 默认的密码认证方式,脚本中存的是校验子 |
| 逐库快照 | pg_dumpall 对每个库各自取快照,彼此时间点不同 |
语法与用法
基本语法
pg_dumpall [connection-option...] [option...]pg_dumpall 没有 dbname 位置参数:它的目标永远是整个集群。连接参数与 pg_dump 基本一致。
最简示例
# 全集群导出到文件
pg_dumpall -h 10.0.0.5 -U postgres -w -f /backup/cluster_$(date +%F).sql
# 只导全局对象(角色 + 表空间)
pg_dumpall -g -f /backup/globals.sql
# 只导角色
pg_dumpall -r -f /backup/roles.sql
# 只导表空间
pg_dumpall -t -f /backup/tablespaces.sql内容范围参数
| 参数 | 长选项 | 含义 |
|---|---|---|
-g | --globals-only | 只导全局对象(角色 + 表空间 + 参数权限),不含任何库 |
-r | --roles-only | 只导角色 |
-t | --tablespaces-only | 只导表空间 |
-a | --data-only | 只导数据 |
-s | --schema-only | 只导结构 |
--no-data | — | 不导数据 |
--no-schema | — | 不导结构 |
--statistics-only | — | 只导优化器统计信息 |
注意 -t 在 pg_dumpall 中的含义与 pg_dump 完全不同:在 pg_dump 里 -t 是 --table,在 pg_dumpall 里是 --tablespaces-only。这是跨工具使用时最容易搞错的参数。
连接与目标库参数
| 参数 | 长选项 | 含义 |
|---|---|---|
-h | --host | 主机 |
-p | --port | 端口 |
-U | --username | 用户名 |
-d | --dbname | 连接字符串(库名会被忽略) |
-l | --database | 用于导出全局对象与发现其他库的初始库名 |
-W | --password | 提示密码 |
-w | --no-password | 不提示密码 |
--role | — | 连接后执行 SET ROLE,以指定角色身份导出 |
-d 与 -l 极易混淆,务必分清:
-d传的是连接参数串(如host=10.0.0.5 port=5432 user=postgres),其中即使写了库名也会被忽略;-l传的是库名,决定全局对象从哪里读、从哪里发现其他库;不给时默认postgres,postgres不存在则用template1。
# -l 指定初始库为 template1(当 postgres 库被删掉时)
pg_dumpall -l template1 -f /backup/cluster.sql过滤与排除
# 排除匹配的数据库(可重复)
pg_dumpall --exclude-database='tmp_*' -f /backup/cluster.sql
# 用过滤文件批量排除(PG17+)
pg_dumpall --filter=exclude.txt -f /backup/cluster.sql过滤文件每行一条规则,格式固定:
# 注释行以 # 开头
exclude database tmp_*
exclude database scratch_*--filter 与 --exclude-database 可以同时使用,--filter 也可以多次指定。文件名写 - 表示从标准输入读取。
输出与清理控制
# 先 DROP 后 CREATE,用于覆盖已有集群
pg_dumpall -c -f /backup/cluster.sql
# DROP 时加 IF EXISTS,抑制「does not exist」错误
pg_dumpall -c --if-exists -f /backup/cluster.sql
# 不导出 GRANT / REVOKE
pg_dumpall -x -f /backup/cluster_nopriv.sql
# 不导出属主变更
pg_dumpall -O -f /backup/cluster_noowner.sql--if-exists 必须与 --clean 一起使用,单独给出无效。
控制导出内容细项
# 不导出表空间定义与归属
pg_dumpall --no-tablespaces -f /backup/cluster.sql
# 不导出 RLS 策略
pg_dumpall --no-policies -f /backup/cluster.sql
# 不导出发布 / 订阅
pg_dumpall --no-publications --no-subscriptions -f /backup/cluster.sql
# 不导出 unlogged 表的数据(结构仍导出)
pg_dumpall --no-unlogged-table-data -f /backup/cluster.sql一致性与锁等待
# 等锁超时即失败,不无限等待
pg_dumpall --lock-wait-timeout=30s -f /backup/cluster.sql
# 跨大版本导出时强制给所有标识符加引号
pg_dumpall --quote-all-identifiers -f /backup/cluster.sql详细说明
全局对象导出:-g 的典型用法
-g 是 pg_dumpall 使用频率最高的模式。它的产物是一份「集群骨架」脚本,可以在任何数据库之前或之后执行(只要有超级用户权限):
pg_dumpall -h 10.0.0.5 -U postgres -w -g -f /backup/globals.sql--
-- Roles
--
CREATE ROLE app_user;
ALTER ROLE app_user WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION NOBYPASSRLS;
ALTER ROLE app_user WITH PASSWORD 'SCRAM-SHA-256$4096:...';
CREATE ROLE readonly;
ALTER ROLE readonly WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN NOREPLICATION NOBYPASSRLS;
GRANT readonly TO app_user;
--
-- Tablespaces
--
CREATE TABLESPACE ssd OWNER postgres LOCATION '/data/tblspc/ssd';
--
-- Databases
--
CREATE DATABASE orders WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8';
ALTER DATABASE orders OWNER TO app_user;注意即使只加 -g,脚本里仍然包含 CREATE DATABASE(属于「发现的其他库」信息的一部分)。如果确实只要角色,用 -r;只要表空间,用 -t。
角色导出:-r
pg_dumpall -r --no-role-passwords -f /backup/roles_nopass.sql-r 只导角色,不含表空间与数据库。它适合「在新集群上先把账号体系建好,再导业务库」的流程,也适合定期对角色定义做版本化快照——角色被误删或误改权限时,这份文件就是救命稻草。
--no-role-passwords 与 -r 是天然搭配:只同步账号结构与成员关系,密码由各自的密钥管理系统注入。
表空间导出:-t
pg_dumpall -t -f /backup/tablespaces.sql产物形如:
CREATE TABLESPACE fast OWNER postgres LOCATION '/data/fast';
CREATE TABLESPACE archive OWNER postgres LOCATION '/data/archive';恢复前必须保证目标服务器上这些目录已存在且属主正确,否则 CREATE TABLESPACE 会失败。这是表空间类恢复事故的头号原因:脚本没问题,但 /data/fast 这个目录在新机器上不存在。
同时提醒:CREATE TABLESPACE 不能运行在事务块内,因此如果恢复脚本被包在 --single-transaction 之类的包装中会失败。
数据装载方式
# 用多值 INSERT,每 500 行一条(兼顾体积与速度)
pg_dumpall --rows-per-insert=500 -f /backup/cluster.sql
# 逐行 INSERT + 显式列名(便于导入到非 PostgreSQL 系统)
pg_dumpall --column-inserts -f /backup/cluster.sql
# 配合 ON CONFLICT DO NOTHING 实现幂等导入
pg_dumpall --column-inserts --on-conflict-do-nothing -f /backup/cluster.sql默认是 COPY,最快也最小。只有当目标不是「原样恢复」而是「把数据搬进另一个体系」时,才值得付出 INSERT 的代价。
--on-conflict-do-nothing 必须搭配 --inserts 或 --column-inserts 使用。
分区表的特殊处理
# 让分区数据统一走根表装载,由目标端重新路由到正确分区
pg_dumpall --load-via-partition-root -f /backup/cluster.sql这个选项解决一个很具体的问题:分区表的 COPY 默认直接写进各个叶子分区。如果两个系统的排序规则(collation)定义不同,同一行数据在目标端可能本该属于另一个分区。让数据统一从根表走,目标端会按自己的分区规则重新判定归属。
典型场景是分区键为 text 且依赖 collation 排序,而源端与目标端的 LC_COLLATE / collation 版本不一致。
密码与认证细节
# 每库都要认证,.pgpass 是唯一可接受的方式
chmod 600 ~/.pgpass
pg_dumpall -h 10.0.0.5 -U postgres -w -f /backup/cluster.sql.pgpass 的匹配规则是按 hostname:port:database:username:password 逐字段匹配,pg_dumpall 连不同库时 database 字段各不相同,因此用 * 通配数据库名是必要写法:
10.0.0.5:5432:*:postgres:MyS3cret如果只写了具体的库名,其他库的连接就会回退到交互式提示,脚本在无人值守场景下直接卡死。
恢复必须使用 psql
# 正确:脚本是纯文本,必须交给 psql 执行
psql -h new-host -U postgres -d postgres -v ON_ERROR_STOP=1 \
-f /backup/cluster.sql
# 错误:pg_dumpall 的输出不是归档,pg_restore 无法读取
pg_restore -d postgres /backup/cluster.sql # 会失败psql 的 -v ON_ERROR_STOP=1 很关键:默认情况下 psql 遇到错误会继续执行后续语句,一个早期的 CREATE ROLE 失败可能导致后面几百条语句在错误的前提下「成功」。加上它可以让脚本在第一个错误处停下。
另一个必须注意的点:恢复时必须连接 postgres(或 template1)这类必然存在的库,因为脚本开头的全局对象语句与 CREATE DATABASE 都与当前库无关,但它们需要一个已存在的连接。连一个不存在的库会导致 psql 直接启动失败。
# 默认连 postgres 库(推荐)
psql -h new-host -U postgres -f /backup/cluster.sql
# 若 postgres 库不存在,连 template1
psql -h new-host -U postgres -d template1 -f /backup/cluster.sql组合策略:全局对象 + 各库归档
这是生产环境最推荐的形态,兼顾了「集群完整性」与「单库可选择性恢复」:
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F)
DIR=/backup/pg/${DATE}
mkdir -p "$DIR"
# 1) 集群骨架:角色 + 表空间
pg_dumpall -h 10.0.0.5 -U postgres -w -g -f "$DIR/globals.sql"
# 2) 逐个业务库用 pg_dump 导成归档
for DB in orders analytics billing; do
pg_dump -h 10.0.0.5 -U postgres -w -Fc -Z zstd:6 \
-f "$DIR/${DB}.dump" "$DB"
done恢复时先执行 globals.sql 建好账号与表空间,再用 pg_restore 逐库恢复:
psql -h new-host -U postgres -v ON_ERROR_STOP=1 -f "$DIR/globals.sql"
for DB in orders analytics billing; do
createdb -h new-host -U postgres "$DB"
pg_restore -h new-host -U postgres -d "$DB" --no-owner -j 4 "$DIR/${DB}.dump"
done这个方案的三个好处:
- 每个库是独立归档,可以单独恢复某一张表、某一段数据;
- 可以并行(多个库的
pg_dump -j甚至可以同时跑); - 全局对象单独成文件,恢复顺序明确可控。
代价是:仍然没有跨库一致性,且脚本要自己维护库清单。
大规模集群的替代方案
pg_dumpall 的逐库串行特性在大集群上是致命的:200 个库 × 每库 3 分钟 ≈ 10 小时,且期间没有跨库一致性。业务规模上去之后,实践中会转向:
| 方案 | 优势 | 代价 |
|---|---|---|
pg_dumpall -g + 并行 pg_dump -Fd -j | 灵活、可并行、可选择性恢复 | 需自维护库清单与调度 |
物理备份 pg_basebackup | 一次搞定整个集群、速度快 | 不能跨版本、只能整集群恢复 |
| pgBackRest / Barman | 增量、压缩、校验、保留策略、云存储 | 需要额外组件与学习成本 |
| 逻辑复制 / 发布订阅 | 可做在线迁移与部分同步 | 不是备份,DDL 需另行同步 |
判断标准很简单:恢复时间目标(RTO)能否被「逐库串行恢复」满足。如果不行,就该往物理备份或专业备份工具迁移。
实战示例
示例一:每日全集群备份
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F_%H%M)
OUT=/backup/pg/cluster_${DATE}.sql
# 需要超级用户;-w 配合 .pgpass 实现免交互
pg_dumpall \
-h 10.0.0.5 -p 5432 -U postgres -w \
--verbose \
-f "$OUT" 2> "${OUT}.log"
# 压缩存储(脚本本身是文本,压缩比通常很高)
gzip -9 "$OUT"
# 校验脚本以预期结尾(一个廉价而有效的完整性检查)
zcat "${OUT}.gz" | tail -3--
-- PostgreSQL database cluster dump complete
--示例二:只导出角色与表空间,重建集群骨架
# 导出(不含密码,便于进版本库)
pg_dumpall -h 10.0.0.5 -U postgres -w -g \
--no-role-passwords \
-f /backup/globals_$(date +%F).sql
grep -c 'CREATE ROLE' /backup/globals_*.sql
grep -c 'CREATE DATABASE' /backup/globals_*.sql14
6# 在新集群上恢复骨架
psql -h new-host -U postgres -v ON_ERROR_STOP=1 \
-f /backup/globals_$(date +%F).sql示例三:排除临时库后导出
cat > /tmp/exclude.txt <<'EOF'
# 排除临时库与测试库
exclude database tmp_*
exclude database scratch_*
exclude database ci_*
EOF
pg_dumpall -h 10.0.0.5 -U postgres -w \
--filter=/tmp/exclude.txt \
-f /backup/cluster_prod.sql
# 确认被排除的库没有出现在脚本里
grep -E '^CREATE DATABASE' /backup/cluster_prod.sqlCREATE DATABASE orders WITH TEMPLATE = template0 ENCODING = 'UTF8';
CREATE DATABASE analytics WITH TEMPLATE = template0 ENCODING = 'UTF8';
CREATE DATABASE billing WITH TEMPLATE = template0 ENCODING = 'UTF8';示例四:跨大版本迁移的完整流程
# 步骤 1:源端(PG 14)导出骨架
/usr/pgsql-18/bin/pg_dumpall -h old-host -U postgres -w \
-g --quote-all-identifiers \
-f /tmp/globals14.sql
# 步骤 2:逐个业务库导出为归档(用 18 的客户端工具连 14 的服务端)
for DB in orders analytics; do
/usr/pgsql-18/bin/pg_dump -h old-host -U postgres -w \
-Fc -Z zstd:6 -f "/tmp/${DB}.dump" "$DB"
done
# 步骤 3:目标端(PG 18)先恢复骨架
psql -h new-host -U postgres -v ON_ERROR_STOP=1 -f /tmp/globals14.sql
# 步骤 4:恢复数据
for DB in orders analytics; do
/usr/pgsql-18/bin/pg_restore -h new-host -U postgres \
-d "$DB" --no-owner -j 4 "/tmp/${DB}.dump"
done
# 步骤 5:目标端跑 ANALYZE,让优化器统计信息可用
for DB in orders analytics; do
/usr/pgsql-18/bin/psql -h new-host -U postgres -d "$DB" -c 'ANALYZE;'
done示例五:校验导出结果
# 完整性与对象计数校验
grep -q 'PostgreSQL database cluster dump complete' /backup/cluster.sql && echo "script complete"更实际的校验手段是计数比对:导出前后对关键对象计数,恢复后再比对。
-- 导出前记录基线
SELECT count(*) AS db_count FROM pg_database WHERE datistemplate = false;
SELECT count(*) AS role_count FROM pg_roles WHERE rolname NOT LIKE 'pg\_%';
SELECT count(*) AS tablespace_count FROM pg_tablespace WHERE spcname NOT LIKE 'pg\_%'; db_count
----------
6
(1 row)
role_count
------------
14
(1 row)
tablespace_count
------------------
2
(1 row)# 从脚本里数一遍,二者应当一致
grep -c '^CREATE DATABASE' /backup/cluster.sql
grep -c '^CREATE ROLE' /backup/cluster.sql
grep -c '^CREATE TABLESPACE' /backup/cluster.sql注意事项
pg_dumpall 不保证跨库一致性
这是最重要的限制。每个库各自取快照,导出时刻不同:
库 A 快照 t0 ──► 库 B 快照 t5 ──► 库 C 快照 t12跨库有业务不变量的场景,不要指望 pg_dumpall 的输出能直接对账。需要一致性就用 --snapshot 手工绑定,或改用物理备份。
输出只能是纯文本,不能用 pg_restore
# 错误
pg_restore -d postgres /backup/cluster.sql
# 正确
psql -d postgres -f /backup/cluster.sql恢复必须连接一个已存在的库
psql 连不上不存在的库就无法开始执行脚本:
# 若目标集群里 postgres 库已被删除,这条会直接失败
psql -h new-host -U postgres -d postgres -f cluster.sql
# 改用 template1
psql -h new-host -U postgres -d template1 -f cluster.sql-t 的含义与 pg_dump 不同
pg_dump -t public.orders # --table,导某张表
pg_dumpall -t # --tablespaces-only,只导表空间--no-role-passwords 会让密码认证全部失效
恢复后角色密码为 NULL,必须逐个重设,否则应用连不上:
# 恢复后需要重建密码
psql -c "ALTER ROLE app_user WITH PASSWORD 'new-secret';"密码校验子在脚本里等于泄露风险
即使不是明文,SCRAM 校验子也可能被离线爆破。脚本必须 0600、加密存储、不进 Git:
umask 077
pg_dumpall -g -f /backup/globals.sql
ls -l /backup/globals.sql-rw------- 1 postgres postgres 8123 Sep 30 03:00 /backup/globals.sqlCREATE TABLESPACE 的目标目录必须预先存在
脚本不会帮你建目录:
# 恢复前先在目标机准备好
mkdir -p /data/tblspc/ssd
chown postgres:postgres /data/tblspc/ssd
chmod 700 /data/tblspc/ssdCREATE TABLESPACE 与 CREATE DATABASE 不能在事务块内
因此不要把整个脚本包进 BEGIN ... COMMIT,也不要指望用单事务恢复获得原子性。
-W 在 pg_dumpall 里会反复提示
每个库一次认证:
# 几乎不可用
pg_dumpall -W -f cluster.sql
# 正确做法
chmod 600 ~/.pgpass # 内容形如 host:port:*:user:pass
pg_dumpall -w -f cluster.sql非超级用户导出会静默丢数据
无权限的库会被报错跳过,脚本看起来「成功」了,实际缺了好几个库。务必用超级用户,或至少检查日志中的权限错误。
恢复脚本会以源端超级用户的身份执行任意 SQL
官方有明确安全警告。处理不可信来源的脚本前必须人工审阅。
--no-sync 只适合测试
它跳过「等待数据落盘」,机器崩溃会留下损坏的 dump:
# 不要在生产备份脚本里用
pg_dumpall --no-sync -f cluster.sql最佳实践
- 生产环境用「
pg_dumpall -g+ 逐库pg_dump -Fc」组合,而不是单个pg_dumpall全量。这样既保住集群骨架,又保留了单库选择性恢复与并行能力。
pg_dumpall -g -f "$DIR/globals.sql"
for DB in $(psql -Atc "SELECT datname FROM pg_database WHERE datistemplate=false AND datname<>'postgres'"); do
pg_dump -Fc -f "$DIR/$DB.dump" "$DB"
done明确接受「无跨库一致性」这个前提,并为跨库业务设计对账或校验机制。不要把它当成原子快照来用。
备份账号用
.pgpass(*通配数据库名),不要用-W。pg_dumpall会多次连接,交互式密码输入在自动化场景下必然失败。
10.0.0.5:5432:*:postgres:MyS3cret只要结构不要密码时用
--no-role-passwords,并把它写进恢复流程——恢复后必须有一步重设密码,否则应用全部认证失败。恢复脚本一律用
psql -v ON_ERROR_STOP=1,让第一个错误就中止,避免在错误前提下「继续成功」。
psql -h new-host -U postgres -v ON_ERROR_STOP=1 -d postgres -f cluster.sql恢复前先准备好表空间目录并验证属主,把「目录不存在」这类低级失败挡在恢复开始之前。
给全局对象脚本单独做版本化归档。角色与权限的变更频率低,但影响面极大;单独保存
-g的输出,可以随时回答「上周这个角色的权限是什么」。用
--quote-all-identifiers处理跨大版本导出,避免目标版本保留字集合变化导致的语法错误。导出后做对象计数校验,比对
pg_database/pg_roles/pg_tablespace的数量与脚本中的CREATE语句数:
SELECT count(*) FROM pg_database WHERE datistemplate = false;
SELECT count(*) FROM pg_roles WHERE rolname NOT LIKE 'pg\_%';定期做恢复演练,重点验证两件事:所有库都能建起来,以及应用账号能按预期连上并有正确权限。备份文件存在不等于恢复可用。
大集群改用 pgBackRest / Barman 或物理备份。当库数量与恢复时间目标冲突时,
pg_dumpall的逐库串行模型就是瓶颈,应尽早迁移到支持增量与并行校验的工具。脚本按机密文件管理:
umask 077、独立目录、独立保留策略,不与业务代码同仓库,不投递到不受控的共享存储。
umask 077
pg_dumpall -g -f /backup/globals.sql下一节
继续学习:pg_restore 恢复