pg_dump 备份策略
High Contrast
Dark Mode
Light Mode
Sepia
Forest
1 min read200 words

pg_dump 备份策略

数据库没有备份等于在裸奔。PostgreSQL 提供了 pg_dump(逻辑备份)和 pg_basebackup(物理备份)两种工具,两者各有适用场景。这一节讲清楚怎么备份、怎么恢复、怎么验证备份是否真的可用。


pg_dump:逻辑备份

# 基础用法:备份整个数据库
pg_dump -U postgres -d myapp_production > backup.sql
# 推荐参数:
pg_dump \
--host=localhost \
--port=5432 \
--username=postgres \
--dbname=myapp_production \
--format=custom \      # 自定义格式(可压缩,支持并行恢复)
--compress=9 \         # 压缩级别(1-9)
--verbose \
--file=myapp_$(date +%Y%m%d_%H%M%S).dump
# 格式选择:
# --format=plain    纯 SQL 文本(可读,但大库恢复慢)
# --format=custom   自定义二进制(推荐:可压缩,支持并行恢复)
# --format=directory 目录格式(支持并行备份)
# --format=tar      tar 包

只备份特定对象

# 只备份特定表
pg_dump -U postgres -d myapp -t orders -t order_items > orders_backup.sql
# 只备份特定 schema
pg_dump -U postgres -d myapp -n public > public_schema.sql
# 排除某些表(如大型日志表)
pg_dump -U postgres -d myapp --exclude-table=audit_logs > backup.sql
# 只备份结构(不含数据)
pg_dump -U postgres -d myapp --schema-only > schema.sql
# 只备份数据(不含结构)
pg_dump -U postgres -d myapp --data-only > data.sql
# 备份整个集群(包含所有数据库和全局对象)
pg_dumpall -U postgres > full_cluster_backup.sql

恢复备份

# 从纯 SQL 文本恢复
psql -U postgres -d myapp_restored < backup.sql
# 从 custom 格式恢复(推荐)
pg_restore \
--host=localhost \
--username=postgres \
--dbname=myapp_restored \
--verbose \
--jobs=4 \             # 并行恢复(只有 custom/directory 格式支持)
myapp_20240322.dump
# 先创建目标数据库
createdb -U postgres myapp_restored
pg_restore -U postgres -d myapp_restored --jobs=4 myapp_20240322.dump
# 只恢复特定表
pg_restore -U postgres -d myapp_restored -t orders myapp_20240322.dump
# 只恢复结构(不含数据)
pg_restore -U postgres -d myapp_restored --schema-only myapp_20240322.dump

自动化备份脚本

#!/bin/bash
# backup_postgres.sh — 每日自动备份脚本
set -e  # 遇错即退
# 配置
DB_NAME="myapp_production"
DB_USER="postgres"
BACKUP_DIR="/var/backups/postgresql"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump"
# 确保备份目录存在
mkdir -p "${BACKUP_DIR}"
# 执行备份
echo "[$(date)] 开始备份 ${DB_NAME}..."
pg_dump \
--username="${DB_USER}" \
--dbname="${DB_NAME}" \
--format=custom \
--compress=9 \
--file="${BACKUP_FILE}"
# 验证备份文件(非空)
if [ ! -s "${BACKUP_FILE}" ]; then
echo "[$(date)] ERROR: 备份文件为空!" >&2
exit 1
fi
FILE_SIZE=$(du -sh "${BACKUP_FILE}" | cut -f1)
echo "[$(date)] 备份完成:${BACKUP_FILE} (${FILE_SIZE})"
# 清理过期备份
find "${BACKUP_DIR}" -name "${DB_NAME}_*.dump" -mtime "+${RETENTION_DAYS}" -delete
echo "[$(date)] 已清理 ${RETENTION_DAYS} 天前的备份"
# 上传到云存储(可选)
# aws s3 cp "${BACKUP_FILE}" "s3://my-db-backups/${DB_NAME}/"
# gsutil cp "${BACKUP_FILE}" "gs://my-db-backups/${DB_NAME}/"
# 添加到 crontab(每天凌晨 2 点备份)
# crontab -e
0 2 * * * /usr/local/bin/backup_postgres.sh >> /var/log/pg_backup.log 2>&1

pg_basebackup:物理备份

# pg_basebackup:备份整个数据库集群的物理文件
# 适合:大数据库(TB 级)、流复制基础备份、PITR
pg_basebackup \
--pgdata=/var/backups/pg_base/$(date +%Y%m%d) \
--format=tar \
--gzip \
--checkpoint=fast \
--wal-method=stream \   # 同时备份 WAL 日志
--progress \
--username=replicator
# 需要在 pg_hba.conf 中允许 replication 连接:
# host replication replicator 0.0.0.0/0 scram-sha-256

PITR:时间点恢复(Point-in-Time Recovery)

# PITR 需要:
# 1. 基础备份(pg_basebackup)
# 2. 持续归档的 WAL 日志
# postgresql.conf 中开启 WAL 归档
# wal_level = replica
# archive_mode = on
# archive_command = 'cp %p /var/backups/pg_wal/%f'
# (生产环境推荐用 WAL-G 或 Barman 工具)
# 恢复到指定时间点
# 1. 停止 PostgreSQL
# 2. 恢复基础备份
# 3. 创建 recovery.conf(PG 12 之前)或 postgresql.conf 中设置:
# restore_command = 'cp /var/backups/pg_wal/%f %p'
# recovery_target_time = '2024-03-22 10:30:00'
# 4. 启动 PostgreSQL,它会自动回放 WAL 到指定时间点

备份验证(最重要的步骤)

# ❌ 常见错误:只备份不验证
# 很多团队在灾难发生时才发现备份损坏或不完整
# ✅ 定期验证备份可恢复性
#!/bin/bash
# verify_backup.sh
BACKUP_FILE="$1"
TEST_DB="backup_verify_$(date +%Y%m%d_%H%M%S)"
# 1. 尝试恢复到测试数据库
createdb -U postgres "${TEST_DB}"
pg_restore -U postgres -d "${TEST_DB}" --jobs=4 "${BACKUP_FILE}"
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "ERROR: 备份恢复失败!" >&2
dropdb -U postgres "${TEST_DB}"
exit 1
fi
# 2. 验证关键表的行数
EXPECTED_ORDERS=$(psql -U postgres -d myapp_production -t -c "SELECT COUNT(*) FROM orders")
ACTUAL_ORDERS=$(psql -U postgres -d "${TEST_DB}" -t -c "SELECT COUNT(*) FROM orders")
if [ "${EXPECTED_ORDERS}" = "${ACTUAL_ORDERS}" ]; then
echo "✅ 备份验证通过:orders 行数匹配 (${ACTUAL_ORDERS})"
else
echo "❌ 备份验证失败:orders 行数不匹配!生产=${EXPECTED_ORDERS},备份=${ACTUAL_ORDERS}"
fi
# 3. 清理测试数据库
dropdb -U postgres "${TEST_DB}"
echo "验证完成,测试数据库已清理"

备份策略建议

📋 最小可行备份方案(小型应用):
- 每日 pg_dump --format=custom
- 保留 30 天
- 存储到不同物理位置(如 S3)
- 每周验证一次恢复
📋 生产环境备份方案(中大型应用):
- pg_basebackup 每日完整物理备份
- WAL 归档(连续 WAL,支持 PITR)
- 工具:WAL-G(轻量)或 Barman(功能完整)
- 3-2-1 原则:3 份副本,2 种介质,1 份异地
- 每月完整恢复演练

下一节流复制与只读副本——备份是"灾后恢复",流复制是"实时容灾"。只读副本还能分担读压力,是高可用架构的基础。