第十二章:备份与恢复

最后更新: 2024-01-01 作者: PostgreSQL Team
页面目录

第十二章:备份与恢复

12.1 备份类型概述

┌─────────────────────────────────────────────────────────────┐
│                    备份策略对比                               │
├─────────────────────────────────────────────────────────────┤
│  逻辑备份    │  pg_dump/pg_dumpall  │  全量/增量/跨版本       │
│  物理备份    │  文件级复制          │  快速、全量              │
│  连续归档    │  WAL + 物理备份      │  PITR、点时间恢复        │
└─────────────────────────────────────────────────────────────┘

12.2 逻辑备份

12.2.1 pg_dump 备份

# 备份单个数据库
pg_dump -U postgres -d mydb -f backup.sql

# 备份压缩格式
pg_dump -U postgres -d mydb -Fc -f backup.dump

# 备份目录格式(并行备份)
pg_dump -U postgres -d mydb -Fd -j 4 -f backup_dir

# 仅备份表结构
pg_dump -U postgres -d mydb --schema-only -f schema.sql

# 仅备份数据
pg_dump -U postgres -d mydb --data-only -f data.sql

# 备份指定表
pg_dump -U postgres -d mydb -t users -t orders -f tables.sql

# 排除指定表
pg_dump -U postgres -d mydb --exclude-table=logs -f backup.sql

# 备份前执行操作
pg_dump -U postgres -d mydb --pre-data-restore="SET session_replication_role = 'replica';" -f backup.sql

12.2.2 pg_dumpall 备份

# 备份所有数据库(包括角色、表空间)
pg_dumpall -U postgres -f all_databases.sql

# 仅备份角色和表空间
pg_dumpall -U postgres --roles-only -f roles.sql
pg_dumpall -U postgres --tablespaces-only -f tablespaces.sql

# 备份全局对象
pg_dumpall -U postgres --globals-only -f globals.sql

12.2.3 备份脚本示例

#!/bin/bash
# backup.sh - PostgreSQL 备份脚本

# 配置
PGHOST=localhost
PGPORT=5432
PGUSER=postgres
BACKUP_DIR=/var/backups/postgresql
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 日志
echo "[$(date)] 开始备份..." >> $BACKUP_DIR/backup.log

# 逻辑备份
pg_dump -h $PGHOST -p $PGPORT -U $PGUSER -Fc mydb -f $BACKUP_DIR/mydb_$DATE.dump

# 删除 7 天前的备份
find $BACKUP_DIR -name "*.dump" -mtime +7 -delete

# 压缩备份
gzip $BACKUP_DIR/mydb_$DATE.dump

echo "[$(date)] 备份完成: mydb_$DATE.dump.gz" >> $BACKUP_DIR/backup.log

12.3 恢复操作

12.3.1 pg_restore 恢复

# 恢复完整数据库
dropdb -U postgres mydb
createdb -U postgres mydb
pg_restore -U postgres -d mydb -c backup.dump

# 恢复压缩格式
pg_restore -U postgres -d mydb backup.dump

# 恢复目录格式
pg_restore -U postgres -d mydb -Fd backup_dir -j 4

# 仅恢复表结构
pg_restore -U postgres -d mydb --schema-only backup.dump

# 仅恢复数据
pg_restore -U postgres -d mydb --data-only backup.dump

# 恢复指定表
pg_restore -U postgres -d mydb --table=users backup.dump

12.3.2 恢复 SQL 文件

# 恢复 SQL 备份
psql -U postgres -d mydb -f backup.sql

# 恢复并显示进度
psql -U postgres -d mydb -f backup.sql 2>&1 | pv -l > /dev/null

# 恢复中遇到错误继续
psql -U postgres -d mydb --set ON_ERROR_STOP=off -f backup.sql

12.4 物理备份

12.4.1 基础备份流程

# 1. 确保 WAL 归档开启
# postgresql.conf:
wal_level = replica
max_wal_senders = 3
archive_mode = on
archive_command = 'test ! -f /var/backups/postgresql/wal/%f && cp %p /var/backups/postgresql/wal/%f'

# 2. 创建备份目录
mkdir -p /var/backups/postgresql/base
mkdir -p /var/backups/postgresql/wal

# 3. 执行基础备份
psql -U postgres -c "SELECT pg_start_backup('base_backup');"
rsync -a --exclude=pg_wal/* /var/lib/postgresql/data/ /var/backups/postgresql/base/
psql -U postgres -c "SELECT pg_stop_backup();"

# 4. 归档当前 WAL
psql -U postgres -c "SELECT pg_switch_wal();"

12.4.2 使用 pg_basebackup

# 基础备份
pg_basebackup -h localhost -U postgres -D /var/backups/postgresql/base -Ft -z -P

# 创建恢复配置
cat > /var/backups/postgresql/base/recovery.conf << 'EOF'
restore_command = 'cp /var/backups/postgresql/wal/%f "%p"'
recovery_target_timeline = 'latest'
EOF

# 完整备份脚本
pg_basebackup -h $PGHOST -p $PGPORT -U $PGUSER -D $BACKUP_DIR/base -Ft -z -P -X stream

12.5 Point-in-Time Recovery (PITR)

12.5.1 配置 WAL 归档

# postgresql.conf

# WAL 级别
wal_level = replica

# 流复制连接数
max_wal_senders = 3

# 启用归档
archive_mode = on

# 归档命令
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'

# 归档格式
archive_timeout = 300  # 5分钟强制归档

12.5.2 PITR 恢复步骤

# 1. 停止 PostgreSQL
sudo systemctl stop postgresql

# 2. 备份当前数据目录
mv /var/lib/postgresql/data /var/lib/postgresql/data.broken

# 3. 恢复基础备份
mkdir /var/lib/postgresql/data
tar -xzf /var/backups/postgresql/base/backup.tar.gz -C /var/lib/postgresql/data

# 4. 创建恢复配置
cat > /var/lib/postgresql/data/recovery.conf << 'EOF'
# 恢复到指定时间点
restore_command = 'cp /var/backups/postgresql/wal/%f "%p"'
recovery_target_time = '2024-06-15 14:30:00+08'
recovery_target_action = 'promote'
EOF

# 或恢复到指定 WAL 位置
cat > /var/lib/postgresql/data/recovery.conf << 'EOF'
restore_command = 'cp /var/backups/postgresql/wal/%f "%p"'
recovery_target_xid = '12345'
recovery_target_action = 'promote'
EOF

# 或恢复到最新可用状态
cat > /var/lib/postgresql/data/recovery.conf << 'EOF'
restore_command = 'cp /var/backups/postgresql/wal/%f "%p"'
recovery_target = 'immediate'
EOF

# 5. 设置权限
chown -R postgres:postgres /var/lib/postgresql/data

# 6. 启动 PostgreSQL
sudo systemctl start postgresql

12.5.3 恢复目标选项

# 恢复到指定时间
recovery_target_time = '2024-06-15 14:30:00+08'

# 恢复到指定事务 ID
recovery_target_xid = '12345'

# 恢复到指定 LSN
recovery_target_lsn = '0/2000000'

# 恢复到指定名称(需要先创建恢复点)
recovery_target_name = 'before_app_update'

# 恢复到 latest
recovery_target = 'latest'

# 恢复到立即可用
recovery_target = 'immediate'

# 是否包含指定时间点之后的事务
recovery_target_inclusive = on

# 恢复到 WAL 之前
recovery_target_timeline = 'latest'

12.6 连续归档脚本

#!/bin/bash
# wal_archive.sh - WAL 归档脚本

WAL_DIR=/var/backups/postgresql/wal
ARCHIVE_DIR=/mnt/nfs/wal_archive

# 归档 WAL 文件
if [ -f "$1" ]; then
    FILE=$(basename $1)
    DEST=$ARCHIVE_DIR/$(date +%Y/%m)/$FILE
    
    mkdir -p $(dirname $DEST)
    cp $1 $DEST
    
    # 上传到云存储
    # aws s3 cp $DEST s3://mybucket/wal/$DEST
    
    echo "[$(date)] Archived: $FILE" >> /var/log/wal_archive.log
fi

12.7 备份策略建议

备份类型 频率 保留时间 用途
逻辑备份(每日) 每天 7-30 天 逻辑恢复、跨版本迁移
物理备份(每周) 每周 4-12 周 快速恢复
WAL 归档 连续 7-30 天 PITR
快照备份 按需 按需 灾难恢复

12.7.1 备份验证

# 验证备份完整性
pg_restore --help > /dev/null

# 测试恢复(隔离环境)
docker run --rm -e POSTGRES_PASSWORD=test postgres:16 \
  -v backup.dump:/backup.dump \
  psql -U postgres -f /backup.dump

# 检查备份大小
ls -lh /var/backups/postgresql/*.dump
du -sh /var/backups/postgresql/base/

12.8 本章小结

备份与恢复关键策略:

主题 工具/方法
逻辑备份 pg_dump, pg_dumpall
物理备份 pg_basebackup, rsync
增量备份 WAL 归档
PITR 恢复点到指定时间
云备份 pgBackRest, Barman

📌 下一章预告

下一章将介绍 PostgreSQL 的高可用与复制技术。