Skip to content

PostgreSQL 完全恢复

核心概念

完全恢复是指将数据库恢复到最新状态,包括所有已提交的事务。在PostgreSQL中,完全恢复通常基于以下技术:

  • 基础备份:数据库的完整副本,作为恢复的起点
  • WAL(Write-Ahead Log)归档:记录所有数据库修改操作的日志文件
  • 恢复模式:PostgreSQL的恢复模式,用于应用WAL日志
  • recovery.signal:用于启动恢复模式的信号文件

完全恢复的主要特点:

  • 恢复后数据库包含所有已提交的事务
  • 恢复过程中会应用所有可用的WAL日志
  • 恢复完成后数据库可以正常使用
  • 支持多种恢复场景,包括灾难恢复、系统迁移等

完全恢复方法

1. 基于基础备份+WAL归档的恢复

这是最常用的完全恢复方法,适用于大多数恢复场景:

恢复步骤

bash
# 1. 停止PostgreSQL服务
pg_ctl stop -D /var/lib/postgresql/15/main

# 2. 清理数据目录(注意:这会删除所有现有数据)
rm -rf /var/lib/postgresql/15/main/*

# 3. 恢复基础备份
pg_basebackup -h backup_server -U replication -D /var/lib/postgresql/15/main -F t -z -X fetch -R

# 或者从本地备份恢复
rsync -a /pg_backups/base/20230101_120000/ /var/lib/postgresql/15/main/

# 4. 配置恢复参数
cat > /var/lib/postgresql/15/main/recovery.signal << EOF
# 恢复命令:从WAL归档目录恢复WAL文件
restore_command = 'cp /pg_backups/wal/%f %p'

# 恢复到最新状态(完全恢复)
# 注意:不要设置recovery_target_time或recovery_target_xid
EOF

# 5. 启动PostgreSQL服务
pg_ctl start -D /var/lib/postgresql/15/main

# 6. 验证恢复结果
psql -h localhost -U postgres -c "SELECT now();"
psql -h localhost -U postgres -c "SELECT * FROM pg_stat_wal_receiver;"  # 如果是主从复制

2. 基于流复制的恢复

适用于主从复制环境,当主库故障时,可以将从库提升为主库:

恢复步骤

bash
# 1. 在从库上停止PostgreSQL服务
pg_ctl stop -D /var/lib/postgresql/15/main

# 2. 检查从库状态
pg_controldata /var/lib/postgresql/15/main | grep -i state

# 3. 将从库提升为主库
pg_ctl promote -D /var/lib/postgresql/15/main

# 4. 启动PostgreSQL服务
pg_ctl start -D /var/lib/postgresql/15/main

# 5. 验证提升结果
psql -h localhost -U postgres -c "SELECT pg_is_in_recovery();"  # 应返回f
psql -h localhost -U postgres -c "SELECT * FROM pg_stat_replication;"  # 如果有其他从库,应显示连接

3. 基于pg_restore的逻辑恢复

适用于逻辑备份的恢复,通常用于选择性恢复或跨版本迁移:

恢复步骤

bash
# 1. 创建目标数据库
createdb -h localhost -U postgres mydb

# 2. 恢复逻辑备份(完全恢复)
pg_restore -h localhost -U postgres -d mydb -j 4 /pg_backups/mydb_backup.dump

# 3. 验证恢复结果
psql -h localhost -U postgres -d mydb -c "SELECT COUNT(*) FROM pg_tables WHERE schemaname = 'public';"

不同场景下的完全恢复

1. 灾难恢复

当生产数据库完全损坏时,使用完全恢复恢复数据库:

bash
# 1. 准备新的服务器
# 安装相同版本的PostgreSQL
# 配置相同的参数

# 2. 恢复基础备份
pg_basebackup -h backup_server -U replication -D /var/lib/postgresql/15/main -F t -z -X fetch -R

# 3. 配置恢复参数
cat > /var/lib/postgresql/15/main/recovery.signal << EOF
restore_command = 'scp backup_server:/pg_backups/wal/%f %p'
EOF

# 4. 启动PostgreSQL服务
pg_ctl start -D /var/lib/postgresql/15/main

# 5. 验证数据完整性
psql -h localhost -U postgres -c "SELECT * FROM critical_table LIMIT 10;"

2. 系统迁移

将数据库从旧服务器迁移到新服务器:

bash
# 1. 在旧服务器上创建基础备份
pg_basebackup -h old_server -U replication -D - -F t -z | ssh new_server "cat > /pg_backups/base/migration_backup.tar.gz"

# 2. 在新服务器上恢复基础备份
mkdir -p /var/lib/postgresql/15/main
tar -xzf /pg_backups/base/migration_backup.tar.gz -C /var/lib/postgresql/15/main/

# 3. 配置恢复参数
cat > /var/lib/postgresql/15/main/recovery.signal << EOF
restore_command = 'scp old_server:/pg_backups/wal/%f %p'
EOF

# 4. 启动PostgreSQL服务
pg_ctl start -D /var/lib/postgresql/15/main

# 5. 切换应用连接到新服务器
# 更新应用配置中的数据库连接信息

3. 版本升级

从旧版本PostgreSQL升级到新版本:

bash
# 1. 在旧版本服务器上创建逻辑备份
pg_dump -h old_server -U postgres -d mydb -F c -f /pg_backups/migration/mydb_backup.dump

# 2. 在新版本服务器上创建数据库
createdb -h new_server -U postgres mydb

# 3. 恢复逻辑备份(完全恢复)
pg_restore -h new_server -U postgres -d mydb -j 4 /pg_backups/migration/mydb_backup.dump

# 4. 验证恢复结果
psql -h new_server -U postgres -d mydb -c "SELECT version();"
psql -h new_server -U postgres -d mydb -c "SELECT * FROM critical_table LIMIT 10;"

完全恢复最佳实践

1. 恢复前准备

  • 备份验证:在恢复前验证备份文件的完整性
  • 环境准备:确保目标环境与源环境配置相似
  • 恢复计划:制定详细的恢复计划,包括步骤、时间和验证标准
  • 权限准备:确保恢复用户具有足够的权限

2. 恢复过程优化

bash
# 优化恢复速度的配置
cat > /var/lib/postgresql/15/main/postgresql.conf << EOF
# 恢复过程中禁用autovacuum
autovacuum = off

# 增加检查点间隔
checkpoint_timeout = 30min
max_wal_size = 4GB

# 增加维护工作内存
maintenance_work_mem = 2GB

# 并行恢复设置
max_parallel_workers_per_gather = 0
max_worker_processes = 8
EOF

3. 恢复后验证

bash
# 1. 检查数据库状态
psql -h localhost -U postgres -c "SELECT pg_is_in_recovery();"  # 应返回f

# 2. 验证数据完整性
psql -h localhost -U postgres -c "SELECT COUNT(*) FROM critical_table;"  # 与预期一致

# 3. 验证功能正常
psql -h localhost -U postgres -d mydb -c "SELECT * FROM get_report();"  # 执行关键业务函数

# 4. 检查日志文件
cat /var/log/postgresql/postgresql-15-main.log | grep -i error  # 无错误

# 5. 更新统计信息
psql -h localhost -U postgres -c "ANALYZE VERBOSE;"

4. 恢复监控

bash
# 监控恢复进度
psql -h localhost -U postgres -c "SELECT * FROM pg_stat_wal_receiver;"  # 流复制恢复

# 查看恢复状态
psql -h localhost -U postgres -c "SELECT * FROM pg_stat_progress_recovery;"  # PostgreSQL 10+

# 监控恢复日志
tail -f /var/log/postgresql/postgresql-15-main.log | grep -i recovery

常见问题(FAQ)

Q1:如何验证WAL归档是否完整?

A1:

bash
# 检查WAL归档目录中的文件数量
ls -la /pg_backups/wal/ | grep -i "^-" | wc -l

# 检查最近的WAL文件是否存在
ls -la /pg_backups/wal/ | sort -k 9 | tail -5

# 使用pg_waldump验证WAL文件完整性
pg_waldump /pg_backups/wal/000000010000000000000001

Q2:完全恢复需要多长时间?

A2:恢复时间取决于以下因素:

  • 基础备份的大小
  • WAL日志的数量
  • 恢复服务器的性能
  • 存储I/O速度

一般来说:

  • 小型数据库(< 100GB):几分钟到几小时
  • 中型数据库(100GB-1TB):几小时到一天
  • 大型数据库(> 1TB):一天以上

Q3:如何加速完全恢复过程?

A3:

bash
# 1. 使用并行恢复
pg_restore -j 8 -d mydb /pg_backups/mydb_backup.dump

# 2. 优化恢复配置
cat >> /var/lib/postgresql/15/main/postgresql.conf << EOF
# 恢复过程中优化
autovacuum = off
checkpoint_timeout = 30min
max_wal_size = 4GB
maintenance_work_mem = 2GB
EOF

# 3. 使用更快的存储设备
# 将恢复目标目录放在SSD上

# 4. 减少WAL日志的数量
# 定期执行基础备份,减少需要应用的WAL日志数量

Q4:恢复过程中出现错误怎么办?

A4:

  1. 查看错误日志:检查PostgreSQL日志文件,了解错误详情
  2. 分析错误原因:根据错误信息分析问题原因
  3. 修复问题
    • 如果是WAL文件缺失,确保WAL归档完整
    • 如果是权限问题,调整文件权限
    • 如果是配置问题,修改配置文件
  4. 重新恢复:修复问题后重新执行恢复过程

Q5:如何验证恢复后的数据库完整性?

A5:

bash
# 1. 检查数据一致性
psql -h localhost -U postgres -c "SELECT COUNT(*) FROM table1;"  # 与预期一致
psql -h localhost -U postgres -c "SELECT * FROM table1 WHERE id = 1;"  # 检查特定数据

# 2. 执行数据库一致性检查
psql -h localhost -U postgres -c "VACUUM ANALYZE VERBOSE;"  # 检查并优化表
psql -h localhost -U postgres -c "REINDEX DATABASE mydb;"  # 重建索引

# 3. 运行应用测试
# 执行应用的单元测试或集成测试,验证数据库功能正常

Q6:完全恢复和时间点恢复有什么区别?

A6:

特性完全恢复时间点恢复
恢复目标最新状态特定时间点
WAL应用所有可用WAL到目标时间点的WAL
恢复命令不需要recovery_target_*参数需要recovery_target_time或recovery_target_xid
适用场景灾难恢复、系统迁移误操作恢复、数据回溯
恢复后状态包含所有已提交事务只包含到目标时间点的事务