PostgreSQL 始终在其集群数据目录的 pg_wal/
子目录下维护一个预写日志 (WAL)。该日志记录了数据库数据文件中的所有更改。该日志主要用于崩溃安全目的:如果系统崩溃,可以通过“重放”自上次检查点以来的日志条目来将数据库恢复到一致状态。然而,该日志的存在使得可以采用第三种策略来备份数据库:我们可以将文件系统级别的备份与 WAL 文件备份结合起来。如果需要恢复,我们恢复文件系统备份,然后从备份的 WAL 文件重放,将系统带到当前状态。此方法比前两种方法更复杂,但具有一些显著的优点。
我们不需要一个完美的、一致的文件系统备份作为起点。备份中的任何内部不一致都将通过日志重放得到纠正(这与崩溃恢复期间发生的情况没有太大区别)。因此,我们不需要文件系统快照功能,只需要tar 或类似的归档工具。
由于我们可以将无限长的 WAL 文件序列用于重放,因此通过继续归档 WAL 文件即可实现连续备份。这对于大型数据库尤其有价值,因为频繁进行完整备份可能不方便。
不必将 WAL 条目重放到末尾。我们可以在任何时候停止重放,并得到数据库在该时刻的精确一致快照。因此,此技术支持时间点恢复:可以将其恢复到自基础备份创建以来数据库的任何时间点状态。
如果我们持续将 WAL 文件系列传输到已加载相同基础备份文件的另一台机器上,我们就拥有一个热备用系统:在任何时候,我们都可以启动第二台机器,它将拥有一个近乎当前的数据库副本。
pg_dump 和 pg_dumpall 不生成文件系统级别的备份,也不能用作连续归档解决方案的一部分。此类转储是逻辑的,不包含足够的信息供 WAL 重放使用。
与纯文件系统备份技术一样,此方法只能支持恢复整个数据库集群,而不能恢复子集。此外,它需要大量的归档存储:基础备份可能很庞大,繁忙的系统会生成大量必须归档的 WAL 流量。尽管如此,在需要高可靠性的许多情况下,它仍然是首选的备份技术。
要成功使用连续归档(许多数据库供应商也称之为“在线备份”)进行恢复,您需要一个连续的归档 WAL 文件序列,该序列至少回溯到备份的开始时间。因此,要开始,您应该在执行第一个基础备份之前设置并测试您的 WAL 文件归档过程。因此,我们首先讨论 WAL 文件归档的机制。
从抽象意义上讲,正在运行的PostgreSQL 系统会生成一个无限长的 WAL 记录序列。该系统将此序列物理上划分为 WAL段文件,这些文件通常为 16MB(尽管段大小可以在initdb 时更改)。段文件被赋予数字名称,反映它们在抽象 WAL 序列中的位置。当不使用 WAL 归档时,系统通常只创建几个段文件,然后通过重命名不再需要的段文件为更高的段号来“回收”它们。假定内容早于最后一个检查点的段文件不再有趣,可以回收。
在归档 WAL 数据时,我们需要在每个段文件被回收使用之前捕获其内容并将其保存到某处。根据应用程序和可用硬件,“将数据保存到某处”可能有很多不同的方法:我们可以将段文件复制到另一台机器上的 NFS 挂载目录,将它们写入磁带驱动器(确保您有办法识别每个文件的原始名称),或者将它们批量打包刻录到 CD 上,或者其他任何方法。为了给数据库管理员提供灵活性,PostgreSQL 尽量不假设归档将如何完成。相反,PostgreSQL 允许管理员指定一个 shell 命令或一个归档库来执行,以将已完成的段文件复制到需要的位置。这可能很简单,就像使用cp
的 shell 命令一样,或者可以调用复杂的 C 函数 — 一切都取决于您。
要启用 WAL 归档,请将 wal_level 配置参数设置为 replica
或更高,将 archive_mode 设置为 on
,在 archive_command 配置参数中指定要使用的 shell 命令,或在 archive_library 配置参数中指定要使用的库。实际上,这些设置将始终放在 postgresql.conf
文件中。
archive_command
中,%p
被替换为要归档的文件路径名,而 %f
被替换为仅文件名。(路径名是相对于当前工作目录的,即集群的数据目录。)如果需要将实际的 %
字符嵌入命令中,请使用 %%
。最简单的有用命令是
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows
这将把可归档的 WAL 段复制到目录 /mnt/server/archivedir
。(这是一个示例,并非建议,并且可能在所有平台上都无法正常工作。)在替换了 %p
和 %f
参数之后,实际执行的命令可能看起来像这样
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
对于每个新文件,都会生成一个类似的命令进行归档。
PostgreSQL 服务器运行的用户将以该用户的身份执行归档命令。由于被归档的 WAL 文件系列实际上包含数据库中的所有内容,因此您需要确保归档数据免受窥探;例如,将数据归档到没有组或世界可读权限的目录中。
归档命令成功时退出状态必须为零,仅当成功时才为零。获得零结果后,PostgreSQL 将假定文件已成功归档,并将其删除或回收。但是,非零状态会告诉PostgreSQL 文件未归档;它会定期重试,直到成功为止。
另一种归档方式是使用自定义归档模块作为 archive_library
。由于此类模块是用 C
编写的,因此创建自己的模块可能比编写 shell 命令需要更多的精力。但是,归档模块可能比通过 shell 归档更有效率,并且它们可以访问许多有用的服务器资源。有关归档模块的更多信息,请参阅 第 49 章。
当归档命令因除服务器关闭过程中使用的 SIGTERM 信号(或 shell 错误且退出状态大于 125,如命令未找到)而终止,或者归档函数发出 ERROR
或 FATAL
时,归档进程会中止,并由 postmaster 重新启动。在这种情况下,失败不会在 pg_stat_archiver 中报告。
归档命令和库通常应设计为拒绝覆盖任何预先存在的归档文件。这是一项重要的安全功能,可防止因管理员错误(例如将两个不同服务器的输出发送到同一个归档目录)而破坏您的归档。建议测试您提出的归档库,以确保它不会覆盖现有文件。
在极少数情况下,PostgreSQL 可能会尝试重新归档之前已归档的 WAL 文件。例如,如果系统在服务器创建归档成功持久记录之前崩溃,服务器将在重新启动后(如果仍启用归档)尝试再次归档该文件。当归档命令或库遇到预先存在的文件时,如果 WAL 文件内容与预先存在的文件内容相同且预先存在的文件已完全持久化到存储中,则应分别返回零状态或 true
。如果预先存在的文件内容与要归档的 WAL 文件内容不同,归档命令或库必须分别返回非零状态或 false
。
上述 Unix 的示例命令通过包含单独的 test
步骤来避免覆盖预先存在的归档。在某些 Unix 平台上,cp
具有 -i
等开关,可以用来不那么冗余地完成相同的操作,但您不应依赖这些而无需验证是否返回了正确的退出状态。(特别是,GNU cp
在使用 -i
且目标文件已存在时将返回零状态,这不是期望的行为。)
在设计您的归档设置时,请考虑如果归档命令或库因需要操作员干预的某些方面或归档空间不足而反复失败会发生什么。例如,如果您在没有自动换盘器的情况下写入磁带,可能会发生这种情况;当磁带填满时,在磁带更换之前,将无法进行任何进一步的归档。您应该确保任何错误条件或对人工操作员的请求都得到适当的报告,以便情况能够尽快得到解决。pg_wal/
目录将继续用 WAL 段文件填充,直到情况得到解决。(如果包含 pg_wal/
的文件系统已满,PostgreSQL 将执行 PANIC 关机。不会丢失已提交的事务,但数据库将保持离线状态,直到您释放一些空间。)
只要归档命令或库能够跟上服务器生成 WAL 数据的平均速率,其速度就不重要。即使归档过程稍有落后,正常操作也会继续。如果归档严重落后,这将增加在发生灾难时会丢失的数据量。它也意味着 pg_wal/
目录将包含大量尚未归档的段文件,这些文件最终可能会超出可用磁盘空间。建议您监控归档过程,以确保其按预期工作。
在编写归档命令或库时,您应该假定要归档的文件名最多可以为 64 个字符长,并且可以包含任何 ASCII 字母、数字和点的组合。不必保留原始相对路径(%p
),但必须保留文件名(%f
)。
请注意,虽然 WAL 归档允许您恢复对PostgreSQL 数据库中数据的任何修改,但它不会恢复对配置文件(即 postgresql.conf
、pg_hba.conf
和 pg_ident.conf
)所做的更改,因为这些是通过手动编辑而不是通过 SQL 操作完成的。您可能希望将配置文件保存在一个位置,该位置将通过您的常规文件系统备份过程进行备份。有关如何重新定位配置文件的信息,请参阅 19.2 节。
归档命令或函数仅在已完成的 WAL 段上调用。因此,如果您的服务器产生的 WAL 流量很少(或有低谷期),则从事务完成到安全记录在归档存储中可能存在很长的延迟。为了限制未归档数据的最长保留时间,您可以设置 archive_timeout 来强制服务器至少以此频率切换到新的 WAL 段文件。请注意,由于强制切换而提前归档的文件仍然与完整填充的文件相同。因此,不建议设置非常短的 archive_timeout
— 它会膨胀您的归档存储。一分钟左右的 archive_timeout
设置通常是合理的。
此外,您可以通过 pg_switch_wal
手动强制切换段,以确保刚完成的事务尽快归档。有关 WAL 管理的其他实用程序函数列在 表 9.97 中。
当 wal_level
为 minimal
时,一些 SQL 命令会被优化以避免 WAL 日志记录,如 14.4.7 节中所述。如果在执行这些语句期间启用了归档或流复制,WAL 将不会包含足够的信息来进行归档恢复。(崩溃恢复不受影响。)因此,wal_level
只能在服务器启动时更改。但是,archive_command
和 archive_library
可以通过配置文件重载来更改。如果您通过 shell 进行归档并希望暂时停止归档,一种方法是将 archive_command
设置为空字符串(''
)。这将导致 WAL 文件在 pg_wal/
中累积,直到重新建立可用的 archive_command
。
执行基础备份的最简单方法是使用 pg_basebackup 工具。它可以创建常规文件形式或 tar 归档形式的基础备份。如果需要比 pg_basebackup 更大的灵活性,您还可以使用低级 API 创建基础备份(参见 25.3.4 节)。
不必担心创建基础备份所需的时间。但是,如果您通常以禁用 full_page_writes
的方式运行服务器,您可能会注意到备份运行时性能有所下降,因为在备份模式下 full_page_writes
会被强制启用。
要使用备份,您需要保留在文件系统备份期间和之后生成的所有 WAL 段文件。为了帮助您做到这一点,基础备份过程会创建一个备份历史文件,该文件会立即存储到 WAL 归档区域。此文件以您基础备份所需的第一段 WAL 文件的名称命名。例如,如果起始 WAL 文件是 0000000100001234000055CD
,则备份历史文件名可能类似于 0000000100001234000055CD.007C9330.backup
。(文件名中的第二部分代表 WAL 文件中的确切位置,通常可以忽略。)一旦您安全地归档了文件系统备份和备份期间使用的 WAL 段文件(如备份历史文件中所指定),所有名称数字小于它们的归档 WAL 段就不再需要恢复文件系统备份,可以删除。但是,您应该考虑保留多个备份集,以确保能够完全恢复您的数据。
备份历史文件只是一个小的文本文件。它包含您为 pg_basebackup 提供的标签字符串,以及备份的开始和结束时间以及 WAL 段。如果您使用标签来标识关联的转储文件,那么归档的历史文件就足以告诉您要恢复哪个转储文件。
由于您必须保留自上次基础备份以来的所有归档 WAL 文件,因此基础备份之间的时间间隔通常应基于您要在归档 WAL 文件上花费的存储量来确定。您还应考虑在必要时恢复需要花费多长时间 — 系统将不得不重放所有这些 WAL 段,如果自上次基础备份以来时间较长,这可能需要一段时间。
您可以使用 pg_basebackup 通过指定 --incremental
选项来创建增量备份。您必须将参数 --incremental
提供给早先来自同一服务器的备份的备份清单。在生成的备份中,非关系文件将完整包含,但某些关系文件可能会被替换为较小的增量文件,其中仅包含自前一个备份以来已更改的块以及重构文件当前版本所需的元数据。
为了确定哪些块需要备份,服务器使用 WAL 摘要,这些摘要存储在数据目录中,位于 pg_wal/summaries
目录下。如果所需的摘要文件不存在,尝试创建增量备份将失败。此目录中的摘要必须涵盖从前一个备份的开始 LSN 到当前备份的开始 LSN 的所有 LSN。由于服务器在建立当前备份的开始 LSN 后会查找 WAL 摘要,因此必要的摘要文件可能不会立即出现在磁盘上,但服务器会等待任何丢失的文件出现。这也适用于 WAL 摘要过程落后的情况。但是,如果必要的已删除文件,或者 WAL 摘要器未足够快地赶上,则增量备份将失败。
恢复增量备份时,不仅需要增量备份本身,还需要所有先前的备份,这些备份对于提供增量备份中省略的块至关重要。有关此要求的更多信息,请参阅 pg_combinebackup。请注意,当集群的校验和状态发生更改时,pg_combinebackup
的使用受到限制;请参阅 pg_combinebackup 限制。
请注意,使用完整备份的所有要求同样适用于增量备份。例如,您仍然需要文件系统备份期间和之后生成的所有 WAL 段文件以及任何相关的 WAL 历史文件。并且您仍然需要创建 recovery.signal
(或 standby.signal
)并执行恢复,如 25.3.5 节中所述。在恢复时需要早期备份可用并使用 pg_combinebackup
是除了所有其他要求之外的附加要求。请记住,PostgreSQL 没有内置机制来确定哪些备份仍然是恢复后期增量备份的基础。您必须自己跟踪完整备份和增量备份之间的关系,并确保在可能需要时不要删除早期备份以用于恢复后期增量备份。
增量备份通常只对相对较大的数据库有意义,其中大部分数据不更改或更改缓慢。对于小型数据库,忽略增量备份的存在并简单地进行完整备份更简单,后者更容易管理。对于大量数据都频繁修改的大型数据库,增量备份的大小不会比完整备份小多少。
仅当重放的起始检查点晚于其依赖的前一个备份时,才可能进行增量备份。如果您在主服务器上进行增量备份,则此条件始终满足,因为每次备份都会触发新的检查点。在备用服务器上,重放从最近的重启点开始。因此,如果自上一个备份以来活动很少,备用服务器的增量备份可能会失败,因为可能没有创建新的重启点。
与其使用 pg_basebackup 来创建完整或增量基础备份,不如使用低级 API。此过程比 pg_basebackup 方法多一些步骤,但相对简单。非常重要的是,这些步骤必须按顺序执行,并且在进行下一步之前要验证前一步的成功。
可以并发运行多个备份(包括通过此备份 API 和通过 pg_basebackup 启动的备份)。
确保 WAL 归档已启用且正常工作。
以具有运行 pg_backup_start
权限的用户(超级用户,或已授予该函数 EXECUTE
权限的用户)连接到服务器(数据库无所谓),然后发出命令
SELECT pg_backup_start(label => 'label', fast => false);
其中 label
是您要用于唯一标识此备份操作的任意字符串。调用 pg_backup_start
的连接必须一直保持到备份结束,否则备份将被自动中止。
在线备份始终在检查点开始时启动。默认情况下,pg_backup_start
会等待下一个计划中的检查点完成,这可能需要很长时间(请参阅配置参数 checkpoint_timeout 和 checkpoint_completion_target)。这通常是首选,因为它最大程度地减少了对正在运行的系统的影响。如果您希望尽快开始备份,请将 true
作为第二个参数传递给 pg_backup_start
,它将请求立即进行检查点,该检查点将尽快完成,并尽可能多地使用 I/O。
使用任何方便的文件系统备份工具(如 tar 或 cpio)(而不是 pg_dump 或 pg_dumpall)执行备份。在此期间,既不需要也不希望停止数据库的正常运行。有关在此备份期间需要考虑的事项,请参阅 25.3.4.1 节。
在与之前相同的连接中,发出命令
SELECT * FROM pg_backup_stop(wait_for_archive => true);
这将终止备份模式。在主服务器上,它还会自动切换到下一个 WAL 段。在备用服务器上,无法自动切换 WAL 段,因此您可能希望在主服务器上运行 pg_switch_wal
来执行手动切换。切换的原因是为了准备在备份期间写入的最后一个 WAL 段文件进行归档。
pg_backup_stop
将返回一行,其中包含三个值。其中第二个字段应写入备份根目录下的名为 backup_label
的文件中。第三个字段应写入名为 tablespace_map
的文件中,除非该字段为空。这些文件对备份的正常工作至关重要,并且必须逐字无修改地写入,这可能需要以二进制模式打开文件。
一旦备份期间活动的 WAL 段文件被归档,您就完成了。由 pg_backup_stop
的第一个返回值标识的文件是构成完整备份文件集所需的最后一个段。在主服务器上,如果启用了 archive_mode
并且 wait_for_archive
参数为 true
,则 pg_backup_stop
在最后一个段已归档之前不会返回。在备用服务器上,archive_mode
必须为 always
才能使 pg_backup_stop
等待。这些文件的归档是自动发生的,因为您已经配置了 archive_command
或 archive_library
。在大多数情况下,这会很快发生,但建议您监控归档系统,以确保没有延迟。如果由于归档命令或库失败而导致归档进程落后,它将继续重试,直到归档成功并且备份完成。如果您希望为 pg_backup_stop
的执行设置时间限制,请设置适当的 statement_timeout
值,但请注意,如果 pg_backup_stop
因此而终止,则您的备份可能无效。
如果备份过程监视并确保备份所需的所有 WAL 段文件都已成功归档,则可以将 wait_for_archive
参数(默认为 true)设置为 false,使 pg_backup_stop
在写入停止备份记录到 WAL 后立即返回。默认情况下,pg_backup_stop
会等待所有 WAL 都归档完毕,这可能需要一段时间。此选项必须谨慎使用:如果 WAL 归档未被正确监视,则备份可能不包含所有 WAL 文件,因此不完整,无法恢复。
一些文件系统备份工具在复制它们正在尝试复制的文件时如果文件发生更改,会发出警告或错误。在活动数据库上创建基础备份时,这种情况是正常的,而不是错误。但是,您需要确保能够区分此类抱怨和真正错误。例如,某些版本的 rsync 会为“消失的源文件”返回单独的退出代码,您可以编写一个驱动程序脚本来接受此退出代码作为非错误情况。另外,某些版本的 GNU tar 在文件在复制过程中被更改时会返回一个与致命错误无法区分的错误代码。幸运的是,GNU tar 版本 1.16 及更高版本在文件在备份过程中发生更改时退出代码为 1,而对于其他错误则为 2。使用 GNU tar 版本 1.23 及更高版本,您可以使用警告选项 --warning=no-file-changed --warning=no-file-removed
来隐藏相关的警告消息。
请确保您的备份包含数据库集群目录(例如,/usr/local/pgsql/data
)下的所有文件。如果您使用的表空间不在该目录之下,请务必也包含它们(并确保您的备份将符号链接作为链接归档,否则恢复将损坏您的表空间)。
但是,您应该从备份中排除集群 pg_wal/
子目录下的文件。这种微小的调整是值得的,因为它可以减少恢复时出错的风险。如果 pg_wal/
是指向集群目录外部某个位置的符号链接,那么很容易安排这一点,这通常出于性能原因设置。您可能还想排除 postmaster.pid
和 postmaster.opts
,它们记录了有关正在运行的 postmaster 的信息,而不是关于最终将使用此备份的 postmaster 的信息。(这些文件可能会使 pg_ctl 感到困惑。)
通常,最好也从备份中排除集群 pg_replslot/
目录下的文件,这样主服务器上存在的复制槽就不会成为备份的一部分。否则,后续使用备份创建备用服务器可能会导致备用服务器上 WAL 文件的无限期保留,并且如果启用了热备用反馈,主服务器上可能会出现膨胀,因为使用这些复制槽的客户端仍然会连接并更新主服务器上的槽,而不是备用服务器上的槽。即使备份仅用于创建新的主服务器,复制槽的内容在新的主服务器上线时很可能已经过时,因此复制它们并不特别有用。
可以从备份中省略 pg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
和 pg_subtrans/
(但不是目录本身)中的文件,因为它们将在 postmaster 启动时进行初始化。
任何以 pgsql_tmp
开头的文件或目录都可以从备份中省略。这些文件在 postmaster 启动时会被删除,目录会在需要时重新创建。
pg_internal.init
文件可以在找到同名文件时从备份中省略。这些文件包含关系缓存数据,这些数据在恢复时总是会重新构建。
备份标签文件包含您传递给 pg_backup_start
的标签字符串,以及 pg_backup_start
运行的时间,以及起始 WAL 文件的名称。因此,在混淆的情况下,可以查看备份文件并确定转储文件来自哪个备份会话。表空间映射文件包含 pg_tblspc/
目录中的符号链接名称以及每个符号链接的完整路径。这些文件不仅仅是为了您的信息;它们的存在和内容对于系统的恢复过程的正常运行至关重要。
也可以在服务器停止时进行备份。在这种情况下,您显然不能使用 pg_backup_start
或 pg_backup_stop
,因此您需要自行跟踪哪个备份是哪个以及相关的 WAL 文件回溯到哪里。通常最好遵循上面的连续归档过程。
好了,最坏的情况已经发生,您需要从备份中恢复。以下是过程
如果服务器正在运行,请停止它。
如果您有足够的空间,请将整个集群数据目录和任何表空间复制到临时位置,以备将来需要。请注意,此预防措施要求您的系统有足够的可用空间来容纳数据库的两个副本。如果您没有足够的空间,至少应保存集群 pg_wal
子目录的内容,因为它可能包含系统在崩溃前尚未归档的 WAL 文件。
删除集群数据目录下的所有现有文件和子目录,以及您正在使用的任何表空间根目录下的文件和子目录。
如果您正在恢复完整备份,您可以将数据库文件直接恢复到目标目录。确保它们以正确的用户(数据库系统用户,而不是 root
!)和正确的权限进行恢复。如果您正在使用表空间,您应该验证 pg_tblspc/
中的符号链接是否已正确恢复。
如果您正在恢复增量备份,您将需要将增量备份以及它直接或间接依赖的所有早期备份恢复到您正在执行恢复的机器上。这些备份需要放置在单独的目录中,而不是您希望正在运行的服务器最终所在的目录。完成后,使用 pg_combinebackup 从完整备份以及所有后续增量备份中提取数据,并将合成的完整备份写入目标目录。如上所述,验证权限和表空间链接是否正确。
删除 pg_wal/
中存在的任何文件;这些文件来自文件系统备份,因此可能已过时而不是最新的。如果您根本没有归档 pg_wal/
,则用正确的权限重新创建它,同时小心确保如果它以前设置为符号链接,则重新建立它。
如果您有未归档的 WAL 段文件(您在步骤 2 中保存的),请将它们复制到 pg_wal/
。(最好复制而不是移动它们,这样如果出现问题并且您必须重新开始,您仍然拥有未修改的文件。)
在 postgresql.conf
中设置恢复配置设置(请参阅 19.5.5 节)并在集群数据目录中创建一个 recovery.signal
文件。您可能还想暂时修改 pg_hba.conf
以防止普通用户连接,直到您确定恢复成功。
启动服务器。服务器将进入恢复模式,并开始读取它需要的归档 WAL 文件。如果由于外部错误而终止恢复,服务器可以简单地重新启动,它将从失败点附近继续恢复。恢复完成后,服务器将删除 recovery.signal
(以防止以后意外再次进入恢复模式),然后开始正常数据库操作。
检查数据库内容,确保已恢复到期望的状态。如果未恢复到期望的状态,请返回步骤 1。如果一切正常,请通过将 pg_hba.conf
恢复正常来允许用户连接。
这一切的关键部分是设置一个恢复配置,该配置描述了您希望如何恢复以及恢复应该运行多远。您绝对必须指定的是 restore_command
,它告诉PostgreSQL 如何检索归档的 WAL 文件段。与 archive_command
类似,这是一个 shell 命令字符串。它可以包含 %f
,它将被替换为所需 WAL 文件的名称,以及 %p
,它将被替换为 WAL 文件要复制到的路径名。(路径名是相对于当前工作目录的,即集群的数据目录。)如果您需要在命令中嵌入实际的 %
字符,请写 %%
。最简单的有用命令是
restore_command = 'cp /mnt/server/archivedir/%f %p'
这将从目录 /mnt/server/archivedir
复制先前归档的 WAL 段。当然,您可以使用更复杂的东西,甚至是一个要求操作员挂载适当磁带的 shell 脚本。
命令在失败时返回非零退出状态很重要。命令将被调用请求不存在于归档中的文件;当被这样询问时,它必须返回非零。这不是错误条件。例外情况是,如果命令被信号(除了用作数据库服务器关闭一部分的 SIGTERM)或 shell 错误(如命令未找到)终止,则恢复将中止,服务器将不会启动。
并非所有请求的文件都将是 WAL 段文件;您还应该期望请求带有 .history
后缀的文件。还要注意 %p
路径的基本名称将与 %f
不同;不要期望它们可以互换。
在归档中找不到的 WAL 段将在 pg_wal/
中查找;这允许使用最近未归档的段。但是,从归档中可用的段将优先于 pg_wal/
中的文件。
通常,恢复将通过所有可用的 WAL 段进行,从而将数据库恢复到当前时间点(或尽可能接近,考虑到可用的 WAL 段)。因此,正常恢复将以 “文件未找到” 消息结束,错误消息的确切文本取决于您选择的 restore_command
。您还可能在恢复开始时看到关于名为 00000001.history
的文件的错误消息。这在简单恢复情况下也是正常的,并且不表示有问题;有关讨论,请参阅 25.3.6 节。
如果您想恢复到某个较早的时间点(例如,就在初级 DBA 删除您的主要事务表之前),只需指定所需的 停止点。您可以按日期/时间、命名恢复点或特定事务 ID 的完成来指定停止点,称为“恢复目标”。截至本文撰写时,只有日期/时间和命名恢复点选项非常实用,因为没有工具可以帮助您准确地识别要使用的事务 ID。
停止点必须晚于基础备份的结束时间,即 pg_backup_stop
的结束时间。您不能使用基础备份恢复到该备份正在进行的某个时间点。(要恢复到该时间点,您必须回溯到上一个基础备份并从那里向前滚动。)
如果恢复发现损坏的 WAL 数据,恢复将在该点停止,并且服务器将不会启动。在这种情况下,可以从头开始重新运行恢复过程,指定一个“恢复目标”,该目标位于损坏点之前,以便恢复可以正常完成。如果由于外部原因(如系统崩溃或 WAL 归档不可访问)而恢复失败,则可以简单地重新启动恢复,它将从失败点附近重新启动。恢复重启的工作方式与正常操作中的检查点类似:服务器定期将所有状态强制写入磁盘,然后更新 pg_control
文件,以指示无需再次扫描已处理的 WAL 数据。
将数据库恢复到先前的某个时间点的能力会产生一些复杂的、类似于科幻故事中的时间旅行和并行宇宙。例如,在数据库的原始历史中,假设您在星期二晚上 5:15 删除了一个关键表,但直到周三中午才意识到错误。您不慌不忙,拿出备份,恢复到星期二晚上 5:14 的时间点,然后启动并运行。在数据库宇宙的这个历史中,您从未删除过该表。但是,如果您后来意识到这不是一个好主意,并希望回到原始历史中的周三早上某个时间点,那么当您的数据库运行时,它会覆盖导致您现在希望能够回溯的时间点的某些 WAL 段文件,您将无法返回。因此,为了避免这种情况,您需要区分在进行时间点恢复后生成的 WAL 记录系列与原始数据库历史中生成的 WAL 记录系列。
为了解决这个问题,PostgreSQL 有一个时间线的概念。每当完成归档恢复时,就会创建一个新的时间线来标识该恢复后生成的 WAL 记录系列。时间线 ID 号是 WAL 段文件名的一部分,因此新时间线不会覆盖先前时间线生成的 WAL 数据。例如,在 WAL 文件名 0000000100001234000055CD
中,前面的 00000001
是十六进制的时间线 ID。(请注意,在其他上下文中,例如服务器日志消息,时间线 ID 通常以十进制打印。)
实际上可以归档许多不同的时间线。虽然这可能看起来是一个无用的功能,但它通常是救命稻草。考虑这种情况:您不确定要恢复到哪个时间点,因此必须通过试错进行几次时间点恢复,直到找到最佳的从旧历史分支的点。没有时间线,这个过程很快就会产生一个难以管理的混乱。有了时间线,您可以恢复到任何先前状态,包括您早期放弃的时间线分支中的状态。
每次创建新时间线时,PostgreSQL 都会创建一个“时间线历史”文件,显示它从哪个时间线分支以及何时分支。这些历史文件对于系统在从包含多个时间线的归档中恢复时选择正确的 WAL 段文件是必需的。因此,它们像 WAL 段文件一样被归档到 WAL 归档区域。历史文件只是小的文本文件,因此保留它们是便宜且合适的(不像段文件那样大)。如果您愿意,可以在历史文件中添加注释,记录您自己关于为何以及如何创建该特定时间线的笔记。当您由于实验而产生大量不同的时间线时,此类注释将特别有价值。
恢复的默认行为是恢复到归档中找到的最新时间线。如果您希望恢复到基础备份创建时的当前时间线或恢复到特定的子时间线(即,您想回到本身是在恢复尝试后生成的某个状态),则需要在 recovery_target_timeline 中指定 current
或目标时间线 ID。您不能恢复到比基础备份更早分支的时间线。
此处提供了一些配置连续归档的技巧。
可以使用PostgreSQL 的备份功能来生成独立的在线备份。这些备份不能用于时间点恢复,但通常比 pg_dump 转储备份和恢复速度快得多。(它们也比 pg_dump 转储大得多,因此在某些情况下速度优势可能会被抵消。)
与基础备份一样,生成独立在线备份的最简单方法是使用 pg_basebackup 工具。如果您在调用它时包含 -X
参数,则使用备份所需的所有预写日志将自动包含在备份中,并且恢复备份不需要特殊操作。
如果归档存储大小是一个问题,您可以使用 gzip 来压缩归档文件
archive_command = 'gzip < %p > /mnt/server/archivedir/%f.gz'
恢复时您将需要使用 gunzip
restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %p'
archive_command
脚本 #许多人选择使用脚本来定义他们的 archive_command
,因此他们的 postgresql.conf
条目看起来非常简单
archive_command = 'local_backup_script.sh "%p" "%f"'
当您想在归档过程中使用不止一个命令时,建议使用单独的脚本文件。这允许所有复杂性都由脚本来管理,该脚本可以用流行的脚本语言(如 bash 或 perl)编写。
脚本中可能解决的需求包括
将数据复制到安全的异地数据存储
将 WAL 文件批量打包,以便每三个小时而不是一次一个地传输
与其他备份和恢复软件进行接口
与其他监控软件进行接口以报告错误
使用 archive_command
脚本时,建议启用 logging_collector。来自脚本的任何写入 stderr 的消息都将出现在数据库服务器日志中,从而可以轻松诊断复杂的配置是否失败。
截至本文撰写时,连续归档技术有几个限制。这些限制很可能会在未来的版本中修复。
如果在创建基础备份时执行了 CREATE DATABASE
命令,然后在基础备份仍在进行时修改了 CREATE DATABASE
复制的模板数据库,则恢复可能会将这些修改也传播到创建的数据库中。这当然是不可取的。为避免此风险,最好在创建基础备份时不要修改任何模板数据库。
CREATE TABLESPACE
命令使用文字绝对路径进行 WAL 日志记录,因此将被重放为具有相同绝对路径的表空间创建。在不同的机器上重放 WAL 时,这可能是不希望的。即使在同一台机器上重放 WAL,但重放到新的数据目录时,这也可能很危险:重放仍将覆盖原始表空间的*.内容。为避免此类潜在的陷阱,最佳做法是在创建或删除表空间后进行新的基础备份。
还应注意,默认的WAL格式由于包含许多磁盘页面快照而相当庞大。这些页面快照旨在支持崩溃恢复,因为我们可能需要修复部分写入的磁盘页面。根据您的系统硬件和软件,忽略部分写入的风险可能很小,在这种情况下,您可以通过关闭页面快照(使用 full_page_writes 参数)来显著减少归档 WAL 文件的总量。(在此之前,请阅读 第 28 章 中的说明和警告。)关闭页面快照不会阻止 WAL 用于 PITR 操作。未来的开发领域是压缩归档 WAL 数据,即使 full_page_writes
处于开启状态,也可以通过删除不必要的页面副本。在此期间,管理员可能希望通过尽可能增加检查点间隔参数来减少 WAL 中包含的页面快照数量。
如果您在文档中发现任何不正确之处、与您在特定功能上的体验不符之处或需要进一步澄清之处,请使用 此表格 报告文档问题。