Skip to content

PostgreSQL 全量恢复

全量恢复是 PostgreSQL 中最基础、最常用的恢复方式,适用于数据库完全损坏、服务器崩溃等灾难性场景。通过还原完整的基础备份并应用后续的 WAL 日志,可以将数据库恢复到某个时间点的状态。本文将详细介绍 PostgreSQL 全量恢复的流程、版本差异处理、最佳实践和常见问题解决方案。

全量恢复概述

全量恢复的适用场景

  • 数据库服务器完全崩溃,无法修复
  • 数据库文件损坏或丢失
  • 误操作导致数据库严重损坏
  • 作为增量恢复或时间点恢复的基础
  • 跨服务器迁移数据库
  • 测试环境重建

全量恢复的原理

  1. 还原基础备份(base backup)到新的数据库目录
  2. 应用基础备份之后生成的 WAL(Write-Ahead Log)日志
  3. 最终将数据库恢复到基础备份完成时的状态或指定时间点

恢复前的准备工作

确认恢复目标

在进行全量恢复前,需要明确以下关键信息:

  • 恢复的目标服务器环境配置(硬件、操作系统、PostgreSQL版本)
  • 基础备份的位置和完整性
  • WAL 日志的可用性和位置
  • 恢复后的数据库用途(测试、生产替换等)
  • 预期的恢复时间和业务影响

准备恢复环境

  1. 停止目标服务器(如果正在运行):

    bash
    pg_ctl -D /path/to/data stop
  2. 清理或重命名目标服务器的数据目录:

    bash
    # 重命名旧数据目录,便于后续分析(如需要)
    mv /path/to/data /path/to/data_old
    # 创建新的数据目录
    mkdir -p /path/to/data
  3. 设置正确的目录权限

    bash
    # 确保数据目录归postgres用户所有
    chown -R postgres:postgres /path/to/data
    chmod 0700 /path/to/data
  4. 准备恢复配置文件

    • PostgreSQL 12+:需要创建 recovery.signal 文件
    • PostgreSQL 11及以下:需要创建 recovery.conf 文件

执行全量恢复

根据备份类型的不同,全量恢复的步骤也有所差异。

使用 pg_basebackup 备份恢复

如果基础备份是通过 pg_basebackup 创建的,恢复步骤如下:

  1. 还原基础备份

    bash
    # 还原 tar 格式备份
    tar -xzf /path/to/backup/base_backup_20251222.tar.gz -C /path/to/data
    
    # 还原 plain 格式备份(直接复制文件)
    rsync -av /path/to/backup/plain_backup/ /path/to/data/
  2. 配置恢复参数

    • PostgreSQL 12+:编辑 postgresql.conf 添加恢复配置
    • PostgreSQL 11及以下:创建 recovery.conf 文件
    sql
    -- PostgreSQL 12+:在 postgresql.conf 中配置
    restore_command = 'cp /path/to/wal_archive/%f "%p"'  -- 从归档恢复WAL
    recovery_target_timeline = 'latest'  -- 恢复到最新时间线
    
    -- PostgreSQL 11及以下:在 recovery.conf 中配置
    restore_command = 'cp /path/to/wal_archive/%f "%p"'
    recovery_target_timeline = 'latest'
  3. 创建恢复信号文件(仅 PostgreSQL 12+):

    bash
    touch /path/to/data/recovery.signal
  4. 启动 PostgreSQL 服务器

    bash
    pg_ctl -D /path/to/data start
  5. 监控恢复进度

    bash
    # 查看日志文件
    tail -f /path/to/data/log/postgresql.log
    
    # 或使用 ps 命令查看恢复进程
    ps aux | grep postgres | grep recovery

使用文件系统备份恢复

如果基础备份是通过文件系统级别的备份(如 rsync、tar、存储快照)创建的,恢复步骤如下:

  1. 确保 PostgreSQL 已停止,且数据目录为空

  2. 还原文件系统备份

    bash
    # 使用 rsync 从备份目录恢复
    rsync -av /path/to/filesystem_backup/ /path/to/data/
    
    # 使用 tar 恢复
    tar -xzf /path/to/filesystem_backup.tar.gz -C /path/to/data
  3. 配置恢复参数:同 pg_basebackup 恢复步骤2

  4. 创建恢复信号文件(仅 PostgreSQL 12+):同 pg_basebackup 恢复步骤3

  5. 启动 PostgreSQL:同 pg_basebackup 恢复步骤4

  6. 验证恢复状态

    sql
    -- 连接到数据库,查看是否处于恢复模式
    SELECT pg_is_in_recovery();
    -- 返回 t 表示正在恢复,返回 f 表示恢复完成

使用 Barman 备份恢复

Barman 是一个常用的 PostgreSQL 备份管理工具,支持快速恢复。

bash
# 使用 Barman 恢复到指定服务器
barman recover pg-server latest /path/to/data --remote-ssh-command "ssh postgres@target-server"

# 或使用 Barman 恢复到本地目录
barman recover pg-server latest /path/to/data

版本差异处理

不同 PostgreSQL 版本在恢复配置上存在差异,主要体现在恢复配置文件的使用上。

PostgreSQL版本恢复配置文件信号文件
12+postgresql.confrecovery.signal
11及以下recovery.conf

在编写恢复脚本时,需要根据目标 PostgreSQL 版本调整配置:

bash
#!/bin/bash

# 检测 PostgreSQL 版本
PG_VERSION=$(pg_config --version | grep -oE '[0-9]+\.[0-9]+' | cut -d. -f1)

if [ "$PG_VERSION" -ge 12 ]; then
  # PostgreSQL 12+ 配置
  echo "restore_command = 'cp /path/to/wal_archive/%f \"%p\"'" >> /path/to/data/postgresql.conf
  echo "recovery_target_timeline = 'latest'" >> /path/to/data/postgresql.conf
  touch /path/to/data/recovery.signal
else
  # PostgreSQL 11及以下配置
  cat > /path/to/data/recovery.conf << EOF
restore_command = 'cp /path/to/wal_archive/%f "%p"'
recovery_target_timeline = 'latest'
EOF
fi

恢复验证

恢复完成后,需要进行全面的验证,确保数据库恢复成功且可用。

基本验证

sql
-- 检查数据库是否正常启动
SELECT version();

-- 检查数据库列表
SELECT datname FROM pg_database;

-- 验证关键数据表数据
SELECT count(*) FROM critical_table;
SELECT * FROM critical_table LIMIT 10;

-- 检查索引状态
SELECT relname, indexrelname, indisvalid FROM pg_index WHERE indisvalid = false;

性能验证

sql
-- 更新统计信息
ANALYZE VERBOSE;

-- 检查表膨胀情况
SELECT 
  schemaname,
  tablename,
  round((n_dead_tup::numeric / NULLIF(n_live_tup, 0) * 100), 2) AS dead_tuple_pct
FROM pg_stat_user_tables 
WHERE n_live_tup > 0 
ORDER BY dead_tuple_pct DESC;

-- 检查缓存命中率
SELECT 
  sum(heap_blks_read) as heap_read,
  sum(heap_blks_hit)  as heap_hit,
  round(sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) * 100, 2) as hit_rate
FROM pg_statio_user_tables;

应用功能验证

  • 运行应用的关键功能测试
  • 执行数据库基准测试,对比恢复前后性能
  • 检查应用连接是否正常

恢复后的最佳实践

  • 立即创建新的基础备份:恢复成功后,立即创建新的基础备份,确保有可用的备份点
  • 重建索引:对于大型表,考虑重建索引以提高性能
    sql
    REINDEX TABLE critical_table;
    -- 或重建整个数据库的索引
    REINDEX DATABASE mydb;
  • 优化恢复参数:根据恢复过程中的经验,调整恢复参数以提高未来恢复的效率
  • 记录恢复过程:详细记录恢复过程、遇到的问题和解决方案,便于未来参考
  • 更新恢复文档:根据实际恢复情况,更新恢复文档和脚本

全量恢复的优化策略

恢复过程优化

  1. 调整检查点参数:在恢复期间提高 checkpoint 间隔,减少恢复期间的 I/O 操作

    sql
    checkpoint_timeout = 30min
    max_wal_size = 10GB
  2. 启用并行恢复:PostgreSQL 12+ 支持并行恢复,可显著提高恢复速度

    sql
    max_parallel_workers_maintenance = 4  -- 根据CPU核心数调整
  3. 优化存储性能:确保恢复目标有足够的 I/O 性能,考虑使用 SSD 存储

  4. 使用快速压缩算法:如果备份使用了压缩,选择快速的压缩算法(如 lz4)而非高压缩比算法(如 xz)

恢复环境优化

  • 使用与源服务器相同或更好的硬件配置
  • 确保恢复环境有足够的磁盘空间
  • 关闭不必要的服务,释放系统资源
  • 考虑使用本地存储而非网络存储进行恢复

常见问题与解决方案

恢复过程中提示缺少 WAL 文件

问题:恢复过程中报错 "could not find WAL segment xxx"

解决方案

  1. 检查 restore_command 是否正确指向 WAL 归档位置
  2. 确认所需的 WAL 文件是否存在于归档目录
  3. 检查 WAL 文件的命名格式是否正确
  4. 如确实缺失,考虑使用 recovery_target_timeline 指定可恢复的时间点
  5. 检查备份过程是否完整,是否有 WAL 文件丢失

恢复后数据库无法启动

问题:恢复后 PostgreSQL 无法启动,日志显示 "invalid primary checkpoint record"

解决方案

  1. 检查基础备份的完整性,确认备份过程中没有中断
  2. 验证数据目录权限是否正确(应为 postgres:postgres 0700)
  3. 检查恢复配置参数是否正确
  4. 尝试使用 pg_resetwal 命令(仅作为最后的手段,可能导致数据丢失):
    bash
    pg_resetwal -D /path/to/data
  5. 考虑重新从备份恢复

恢复时间过长

问题:恢复过程耗时超出预期

解决方案

  1. 确保恢复环境有足够的 I/O 性能
  2. 增加 checkpoint_timeoutmax_wal_size 减少恢复期间的检查点
  3. 启用并行恢复(PostgreSQL 12+)
  4. 对于非常大的数据库,考虑使用增量备份策略
  5. 考虑使用更快的存储介质
  6. 优化恢复命令,如使用 rsync 的 --no-checksum 选项

恢复后数据不一致

问题:恢复后发现部分数据缺失或不一致

解决方案

  1. 检查备份的完整性和一致性
  2. 确认 WAL 日志是否完整,没有缺失
  3. 检查恢复过程中是否有错误日志
  4. 考虑从更完整的备份恢复
  5. 如可能,使用其他备份进行补充恢复

全量恢复与其他恢复方式的结合

全量恢复 + 时间点恢复(PITR)

全量恢复可以作为时间点恢复的基础,实现更精确的恢复:

  1. 先执行全量恢复到基础备份状态
  2. 配置恢复目标时间或 LSN:
    sql
    -- PostgreSQL 12+:在 postgresql.conf 中配置
    recovery_target_time = '2025-12-22 14:30:00+08'  -- 恢复到指定时间点
    recovery_target_action = 'promote'  -- 到达目标后自动提升为主库
    
    -- 或指定 LSN
    recovery_target_lsn = '1/23456789'  -- 恢复到指定LSN位置
  3. 启动数据库,自动应用 WAL 到指定时间点

全量恢复 + 增量恢复

对于大型数据库,可以结合增量备份减少恢复时间:

  1. 恢复最近的全量备份
  2. 应用增量备份(如通过 pg_probackup、Barman 或 pgBackRest 的增量备份)
  3. 应用后续的 WAL 日志
  4. 完成恢复

生产环境恢复示例脚本

以下是一个完整的生产环境全量恢复脚本示例:

bash
#!/bin/bash

# 恢复配置
PG_DATA_DIR="/pgdata/data"
BACKUP_DIR="/pgbackup/full_backup_20251222"
WAL_ARCHIVE_DIR="/pgbackup/wal_archive"
PG_VERSION="15"
RECOVERY_TARGET="latest"

# 停止PostgreSQL服务
echo "Stopping PostgreSQL..."
systemctl stop postgresql-${PG_VERSION}

# 备份旧数据目录(可选)
if [ -d "${PG_DATA_DIR}" ]; then
  echo "Backing up old data directory..."
  mv ${PG_DATA_DIR} ${PG_DATA_DIR}_$(date +%Y%m%d_%H%M%S)
fi

# 创建新的数据目录
echo "Creating new data directory..."
mkdir -p ${PG_DATA_DIR}
chown -R postgres:postgres ${PG_DATA_DIR}
chmod 0700 ${PG_DATA_DIR}

# 还原基础备份
echo "Restoring base backup..."
tar -xzf ${BACKUP_DIR}/base_backup.tar.gz -C ${PG_DATA_DIR}

# 配置恢复参数
echo "Configuring recovery parameters..."
cat >> ${PG_DATA_DIR}/postgresql.conf << EOF
# Recovery configuration
restore_command = 'cp ${WAL_ARCHIVE_DIR}/%f "%p"'
recovery_target_timeline = '${RECOVERY_TARGET}'
checkpoint_timeout = 30min
max_wal_size = 10GB
max_parallel_workers_maintenance = 4
EOF

# 创建recovery.signal文件(PostgreSQL 12+)
echo "Creating recovery.signal file..."
touch ${PG_DATA_DIR}/recovery.signal
chown postgres:postgres ${PG_DATA_DIR}/recovery.signal

# 启动PostgreSQL服务
echo "Starting PostgreSQL..."
systemctl start postgresql-${PG_VERSION}

# 监控恢复进度
echo "Monitoring recovery progress..."
sleep 5

# 检查恢复状态
while true; do
  RECOVERY_STATUS=$(sudo -u postgres psql -t -c "SELECT pg_is_in_recovery();")
  if [ "$RECOVERY_STATUS" = " t" ]; then
    echo "Recovery in progress..."
    sleep 10
  else
    echo "Recovery completed!"
    break
  fi
done

# 验证恢复结果
echo "Verifying recovery..."
sudo -u postgres psql -c "SELECT version();"
sudo -u postgres psql -c "SELECT count(*) FROM pg_database;"
echo "Recovery process completed successfully!"

总结

全量恢复是 PostgreSQL 数据库恢复的基础手段,适用于各种灾难性故障场景。成功的全量恢复需要:

  • 完整可用的基础备份和 WAL 日志
  • 正确的恢复配置和步骤
  • 充分的恢复前准备
  • 全面的恢复后验证
  • 持续的恢复过程监控

作为DBA,应该:

  • 定期测试恢复流程,确保备份可用且恢复步骤正确
  • 记录详细的恢复文档,包括备份位置、恢复步骤和验证方法
  • 优化恢复环境和参数,提高恢复效率
  • 根据实际需求选择合适的恢复策略(全量、增量、时间点)
  • 持续学习和更新恢复知识,适应新版本的变化

通过合理的备份策略和熟练的恢复操作,可以最大限度地减少数据库故障带来的业务影响,确保数据的安全性和可用性。