PostgreSQL 生产环境备份恢复与高可用实战

「 数据丢了、主库挂了、表膨胀了、连接被打满------做 PG 运维,这几个场景迟早会撞上。今天把备份恢复、流复制、膨胀治理、连接池这几块串起来讲,命令都能直接复制用。 」

一、逻辑备份:pg_dump 日常兜底

pg_dump 只备份单个库,不影响线上读写,适合每天定时全量某个库。

|-------------------|----------------------------------------------------------------------------|
| 场景 | 命令 |
| 自定义格式备份(建议,可并行恢复) | pg_dump -U postgres -h 127.0.0.1 -p 5432 -d mydb -F c -f /backup/mydb.dump |
| 纯 SQL 文本备份 | pg_dump -U postgres -d mydb -f /backup/mydb.sql |
| 只备份某张表 | pg_dump -U postgres -d mydb -t public.orders -f /backup/orders.sql |
| 恢复自定义格式 | pg_restore -U postgres -d mydb /backup/mydb.dump |
| 恢复 SQL 文本 | psql -U postgres -d mydb -f /backup/mydb.sql |

注意:pg_dump 不备份角色和表空间,要带全局对象用 pg_dumpall -U postgres -f /backup/globals.sql(角色、权限、表空间定义)。PGCA 考试常考 pg_dump 与 pg_dumpall 的边界。

二、物理备份 + PITR:误删数据也能回到时间点

逻辑备份只能回到"备份时刻",物理备份 + WAL 归档才能做时间点恢复(PITR),找回误删前的状态。

前提(主库 postgresql.conf):

|-----------------|---------------------|----------------|
| 参数 | 建议值 | 说明 |
| wal_level | replica | 必须,否则 WAL 信息不足 |
| archive_mode | on | 开启归档 |
| archive_command | 'cp %p /archive/%f' | 归档脚本,%p 源 %f 名 |

基础备份与恢复步骤:

|--------------|--------------------------------------------------------------------------------------------------------------------------------------|
| 场景 | 命令 |
| 基础备份(tar 压缩) | pg_basebackup -U repl -h primary -p 5432 -D /backup/base -Ft -Z 5 -P |
| 恢复时指定回放目标 | 在 postgresql.auto.conf 写 restore_command = 'cp /archive/%f %p' 和 recovery_target_time = '2026-08-28 10:00:00',并放 recovery.signal 后启动 |
| 确认已回到目标时间点 | 看日志 recovery complete,或 SELECT pg_is_in_recovery(); 返回 f |

关键:PITR 靠的是"基础备份 + 这段时间的 WAL",所以 archive_command 必须真的把 WAL 落盘成功,否则恢复链断。PGCE 考点常把"只做基础备份没开归档"设为错题。

三、流复制:主库挂了 standby 顶上

一主一从,主库写、从库可读,主挂了切从库继续服务。

主库准备(postgresql.conf):

|-----------------------|---------|
| 参数 | |
| wal_level | replica |
| max_wal_senders | 10 |
| max_replication_slots | 10 |

建复制账号、拉从库:

|-----------------|---------------------------------------------------------------------------------------------------------|
| 场景 | 命令 |
| 建复制专用角色 | CREATE ROLE repl REPLICATION LOGIN PASSWORD 'StrongPwd2026'; |
| 拉全量并直接成 standby | pg_basebackup -U repl -h primary -p 5432 -D /data/pgdata_standby -Fp -X stream -P --write-recovery-conf |

-R 会自动在从库生成 standby.signal 和 primary_conninfo,拉起来就是备库,不用手改配置。

监控复制状态:

|-------------|-------------------------------------------------------------------------------------------------------------------|
| 场景 | 命令(在主库执行) |
| 看从库连接和延迟 | SELECT application_name, state, write_lag, flush_lag, replay_lag FROM pg_stat_replication; |
| 从库看接收状态 | SELECT * FROM pg_stat_wal_receiver; |
| 看回放落后多少秒 | SELECT now() - pg_last_xact_replay_timestamp() AS replay_lag; |
| 看落后字节数(WAL) | SELECT application_name, pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes FROM pg_stat_replication; |

四、表膨胀治理:vacuum 不是万能药

PG 用 MVCC,UPDATE/DELETE 旧版本不立刻回收,dead tuple 多了表就膨胀、索引也跟着大。

|---------------------------|----------------------------------------------------------------------------------------------------|
| 场景 | 命令 |
| 整库清理 + 更新统计(先 \c mydb) | VACUUM (VERBOSE, ANALYZE); |
| 更省事:命令行直接对库做(不加 -f 就不会锁表) | vacuumdb -d mydb -v -z |
| 单表精准清理(VACUUM 跟表名不是库名) | VACUUM (VERBOSE, ANALYZE) public.orders; |
| 看哪些表死元组多 | SELECT schemaname, relname, n_dead_tup FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; |
| 单表调小自动清理阈值 | ALTER TABLE orders SET (autovacuum_vacuum_scale_factor = 0.05); |

⚠ VACUUM FULL 会锁表并重建,业务高峰期千万别跑,会卡死写入。膨胀严重优先调 autovacuum 参数(autovacuum_max_workers、autovacuum_naptime)让它自己慢慢收。PGCA 常考 VACUUM 与 VACUUM FULL 的区别------前者在线不锁表,后者排他锁。

五、连接池 pgBouncer:挡住连接风暴

应用直连 PG,max_connections 一撑满新连接就进不来。pgBouncer 在前面做连接复用,几百个应用连接复用几十个后端连接。

pgbouncer.ini 关键配置:

|-----------------|---------------------------------------------|----------|
| 配置项 | | 说明 |
| databases 段 | mydb = host=127.0.0.1 port=5432 dbname=mydb | 后端真实库 |
| listen_port | 6432 | 应用连这个端口 |
| pool_mode | transaction | 事务级复用,最稳 |
| auth_type | md5 | 按需 |

常用运维:

|---------|--------------------------------------------|
| 场景 | 命令 |
| 应用改连池端口 | psql -h 127.0.0.1 -p 6432 -U appuser mydb |
| 看连接池占用 | SHOW POOLS; |
| 热加载配置 | kill -SIGHUP $(cat /var/run/pgbouncer.pid) |

pool_mode 三种:session(整个会话占用)、transaction(事务结束即还)、statement(每条语句还,有游标或带事务的语句会报错)。大多数 web 应用用 transaction 最稳。

六、执行计划与索引:慢查询先 EXPLAIN

别猜,先 EXPLAIN (ANALYZE, BUFFERS) 看真实执行。

|--------------|----------------------------------------------------------------------------------------|
| 场景 | 命令 |
| 看真实执行计划 | EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 123; |
| 线上建索引不锁表 | CREATE INDEX CONCURRENTLY idx_orders_user ON orders(user_id); |
| 重建大索引不锁表 | REINDEX INDEX CONCURRENTLY idx_orders_user; |
| 找从没被用过的索引 | SELECT schemaname, relname, indexrelname FROM pg_stat_user_indexes WHERE idx_scan = 0; |
| 统计信息过期导致走错计划 | ANALYZE orders; |

⚠ CREATE INDEX / REINDEX 不加 CONCURRENTLY 会锁表,大表在高峰期加索引直接卡业务。CONCURRENTLY 不能写在事务块里。

七、日常避坑清单

|------------------|------------------------------------------------------------|
| | 正确姿势 |
| fsync=off 提升性能 | 生产绝对不能关,掉电就丢数据 |
| 高峰期跑 VACUUM FULL | 改调 autovacuum,或低峰再操作 |
| 连接数不设上限猛涨 | 前面套 pgBouncer,控 max_connections |
| 长事务不提交 | 设 idle_in_transaction_session_timeout、statement_timeout 兜底 |
| WAL 归档失败不报警 | 监控归档目录和 pg_stat_archiver |

▲ 一图速查:核心命令汇总(建议收藏)

小结

备份恢复(pg_dump / pg_basebackup + PITR)、流复制高可用、膨胀治理、连接池、执行计划------这五块串起来,PG 生产环境大半问题都有抓手。命令都放进表格里,复制到终端就能用。先把备份和流复制这两块搭起来,比什么都重要。

相关推荐
程序员-Benothing1 小时前
MySQL 中的 MVCC 是什么?如果没有 MVCC,会有什么影响?
数据库·mysql
Zenova EdgeOS1 小时前
工业网关心跳机制:从 Keepalive 到健康判定的工程实战
大数据·网络·数据库·边缘计算·工业网关
疯狂打码的少年1 小时前
【数据库技术】关系完整性约束(实体/参照/用户定义)
运维·服务器·数据库·笔记
派小汤2 小时前
Harmony2.2.0通过RdbStore实现通用类操作本地SQLite数据库
数据库·sql·sqlite·鸿蒙·鸿蒙系统
程序员-Benothing3 小时前
MySQL 中的事务隔离级别有哪些?默认的事务隔离级别是什么?为什么选择这个级别?
数据库·mysql
lv__pf3 小时前
【TL mysql 3】
数据库
xiaomici4 小时前
Datasphere的数据merge
数据库
小林ixn4 小时前
从零设计一个博客系统的数据库:表结构、索引与约束的实战思考
数据库·后端·mysql
Yang96115 小时前
一台顶三台:鼎讯DLJ-1在不同故障类型中的模式切换数据复盘
服务器·网络·数据库