无论是自然灾害还是技术事件,灾难来袭都会对您的网络、数据库和最终用户造成影响,造成代价高昂的宕机和数据损坏。数据损坏,无论是由硬件故障(例如磁盘损坏或内存故障)、软件故障(例如操作系统错误)还是人为失误(例如意外覆盖)引起的,对任何管理员来说都是可怕的。
PostgreSQL 数据库通常是您运营的可靠基石。然而,当灾难来袭时,它可能会迅速演变成无法访问的负担,导致应用程序陷入瘫痪,并使关键数据面临风险。PostgreSQL 17 为您提供了增强的武器库来正面应对这一挑战,它提供了内置工具,例如pg_amcheck 用于精确定位损坏的工具、改进的故障转移槽同步功能(可在恢复期间保持复制完整),以及更细粒度的预写日志 (WAL) 控制,可实现精确的恢复。在本篇博文中,我们将深入探讨灾难管理流程,为您提供实际的命令和预期输出,以便准确诊断损坏并有效地恢复,无论您是从强大的备份中恢复,还是从没有安全网的瘫痪集群中抢救残骸。通过正确的方法,您可以将恐慌转化为计划,并恢复数据库的秩序。
步骤一:检测 PostgreSQL 中的损坏
损坏通常不会轻易出现;它会通过失败的查询、崩溃的日志或启动错误潜入。识别损坏是解决问题的第一步。
检查 PostgreSQL 日志文件首先检查日志文件。通常,您可以在或
中找到日志文件。在日志文件中,条目标头指示日志条目的严重性级别;例如:
/var/log/postgresql/$PGDATA/pg_log
ERROR: could not read block 128 in file "base/16384/12571": read only 0 of 8192 bytes PANIC: invalid page in block 42 of relation base/16384/16728 LOG: startup process (PID 1234) was terminated by signal 6: Aborted FATAL: the database system is in recovery mode
严重性级别表示:
- 错误:读取失败,可能是磁盘级别问题。
- 恐慌:严重损坏,PostgreSQL 崩溃以防止进一步损坏。
- 严重:服务器正在尝试从非正常关机中恢复。
command:pg_amcheck -d mydb --all
如果您的数据库健康,pg_amcheck则返回:
No failures detected in database "mydb"
如果pg_amcheck检测到损坏:
heap table "public.orders": block 128 is not valid btree index "public.orders_idx": block 22 contains invalid tuple
最佳实践:调用pg_amcheck进行 更深入的验证时,请包含 --heapallindexed 或 --rootdescend 标志。
可选:验证校验和。
如果您–data-checksums 在初始化 PostgreSQL 集群(运行 initdb 时)时指定了该标志,则可以使用pg_checksums 工具检测跨数据块的低级文件损坏。pg_checksums 提供完整性保障,允许 PostgreSQL 验证磁盘上的数据是否由于位腐烂、磁盘故障或硬件故障而被意外更改。
pg_checksums 必须在 PostgreSQL 服务器停止时运行,并且仅在集群初始化期间启用校验和的情况下才会起作用。pg_checksums 在非正常关机、系统崩溃或怀疑磁盘问题时,运行此命令尤为重要。
干净的报告表示您的数据块完好无损,而校验和失败则表示表或索引文件中存在特定的块级损坏。SQL 查询可以将这些文件标识符(例如 base/16384/12571)映射到表名。
该工具不会修复任何内容——它只是报告哪些数据块已损坏,以便您采取适当的步骤进行恢复(例如,从备份中恢复、隔离受影响的表或调查硬件问题)。请务必在生产环境中启用校验和,以提高可观察性并更早地检测到损坏。
sudo systemctl stop postgresql
pg_checksums -c -D /var/lib/pgsql/data
Checksum verification failed in file "base/16384/12571", block 128
最佳实践:初始化每个新数据库时启用校验和验证。要在新集群上启用 pg_checksums,–data-checksums 请在调用 initdb 时包含以下命令:
initdb --data-checksums -D /var/lib/pgsql/data
步骤二:立即停止 PostgreSQL
当发现数据损坏时,您应该通过停止服务来防止进一步的损坏:
sudo systemctl stop postgresql
postgresql.service - PostgreSQL RDBMS
Active: inactive (dead)
步骤三:从已知良好的备份恢复
pgBackRest 是一款强大高效的 PostgreSQL 备份和恢复解决方案,支持完整备份、差异备份和增量备份,并具备压缩、加密、并行处理和异地存储(例如 S3)等功能。pgBackRest 旨在以高性能处理大规模环境,并将对数据库服务器的影响降至最低。pgBackRest 还通过提供自动恢复流程、存档管理和时间点恢复 (PITR) 功能,简化了灾难恢复。
使用 pgBackRest 清理和恢复集群
恢复之前,请备份损坏的(旧)数据目录:
cp -rf /var/lib/pgsql/data /var/lib/pgsql/data_backup
确认备份已保存后,擦除旧数据目录:
rm -rf /var/lib/pgsql/data/*
然后,从上次已知的良好备份中恢复:
pgbackrest --stanza=main restore --db-path=/var/lib/pgsql/data
INFO: restore command begin
INFO: restored file base/16384/12571 (16MB, 50%) checksum verified
INFO: restore command end: completed successfully
然后,正确的所有权:
恢复数据库后,请确保数据目录正确归 PostgreSQL 用户所有:
chown -R postgres:postgres /var/lib/pgsql/data
步骤四:使用时间点恢复 (PITR)
使用支持时间点恢复的备份策略 将允许您在损坏发生之前停止。
配置恢复
将以下命令添加到您的 postgresql.conf 文件:
restore_command = 'cp /mnt/backup/wal/%f %p'
recovery_target_time = '2025-03-25 13:59:00 UTC'
创建恢复触发器:
touch /var/lib/pgsql/data/recovery.signal
启动 PostgreSQL 时,您可以观察服务器恢复到您在参数中指定的时间点
recovery_target_time :
sudo systemctl start postgresql
LOG: starting point-in-time recovery to "2025-03-25 13:59:00 UTC"
LOG: restored log file "000000010000000000000005" from archive
LOG: consistent recovery state reached
LOG: recovery stopping before commit of transaction 123
LOG: database system is ready to accept connections
最佳实践:使用支持时间点恢复的备份策略可以让您恢复到损坏之前的干净状态。
步骤五:尽力挽救
如果您没有备份但某些表仍然有效,则可以使用pg_dump 和其他 Postgres 工具来提取您可以提取的内容。
首先,用于pg_dump保存任何可读表及其数据的定义:
pg_dump -t customers mydb > customers.sql
SELECT count(*) FROM customers;
然后,创建一个新的集群:
initdb -D /var/lib/pgsql/new_data --data-checksums
pg_ctl -D /var/lib/pgsql/new_data -l logfile start
然后,将恢复的数据恢复到新的集群中:
createdb -h /var/lib/pgsql/new_data newdb psql -d newdb < customers.sql
最佳实践:为所有不容丢失的数据制定可靠的备份策略。在危机时刻,您可以使用以下步骤恢复已挽救的数据,但恢复可能不完整,您仍然需要手动检查并重新创建可能已损坏的架构对象。这些步骤将使您能够在干净的环境中进行部分恢复。
步骤六:pg_resetwal作为最后的手段
pg_resetwal 是一个低级 PostgreSQL 实用程序,用于强制重置数据库集群的预写日志 (WAL),通常在服务器因 WAL 文件丢失或损坏而无法启动时作为最后的手段使用。此工具应谨慎使用,因为它会绕过正常的崩溃恢复,并可能导致数据不一致或近期事务丢失。仅当您确定数据文件处于一致状态或尝试从故障系统中恢复部分数据时,运行此工具才是安全的。
仅在所有其他方法都失败时才使用此工具。它会重置 WAL 记录,从而导致事务丢失和损坏的风险。
pg_resetwal -f /var/lib/pgsql/data
sudo systemctl start postgresql
LOG: WAL reset performed
LOG: database system is ready to accept connections
注意:自上次检查点以来添加的数据可能会丢失;您应该在咨询专家后再继续操作。
步骤七:防止未来的数据损坏
别让这种事情再次发生。PostgreSQL 17 为您提供了出色的工具来保护您的数据。总而言之,帮助您从灾难中恢复的最佳实践如下:
初始化集群时启用校验和
initdb --data-checksums -D /var/lib/pgsql/data
使用 pgBackRest 自动备份
pgbackrest --stanza=main --type=full backup
pgbackrest --stanza=main --type=incr backup
使用以下方式定期进行完整性检查 pg_amcheck
pg_amcheck -d mydb --all > /var/log/pg_amcheck_$(date +%F).log
创建一个简单的 cron 作业并使用以下命令运行:pg_amcheck
0 2 * pg_amcheck -d mydb --all > /var/log/pg_amcheck_$(date +\%F).log 2>&1
步骤八:拥抱高可用性和 WAL 归档
如果您已配置允许您配置高可用性并维护备份节点的复制解决方案,则可以在主节点发生故障时提升副本:
pg_ctl promote -D /var/lib/pgsql/standby
确保已为 PITR 配置了 WAL 归档;在 postgresql.conf 文件中,设置:
archive_mode = on archive_command = 'cp %p /mnt/wal_archive/%f'
结论
PostgreSQL 中的灾难恢复需要快速行动和周密计划,而 PostgreSQL 17 显著增强了您的响应能力。借助集成工具(例如pg_amcheck用于实时损坏检测、用于可靠备份和 PITR 的 pgBackRest 以及pg_resetwal用于最后手段恢复的工具),您可以处理最严重的故障。无论是从干净的备份还原、恢复到灾难发生前的状态,还是从损坏的集群中挽救数据,本文都将通过实际命令和实用建议指导您完成每个步骤。
请记住,恢复并非始于故障发生,而是始于准备。请设定目标,将您的 PostgreSQL 数据库转变为一个具有弹性、自我防御能力的系统,具体方法是启用数据校验和、自动备份、监控损坏情况,并使用 WAL 归档设置高可用性 。在 PostgreSQL 中,灾难可能会发生,但只要使用正确的工具和方法,就可以进行恢复。
原文地址:https://www.pgedge.com/blog/8-steps-to-proactively-handle-postgresql-database-disaster-recovery
原文作者:Ibrar Ahmed




