在任何时候,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
之类的开关,可以用来以更简洁的方式做同样的事情,但是您不应该在不验证是否返回正确的退出状态的情况下依赖这些开关。(特别是,当使用-i
并且目标文件已存在时,GNU cp
将返回状态零,这不是期望的行为。)
在设计您的归档设置时,请考虑如果归档命令或库由于某些方面需要操作员干预或归档空间不足而反复失败会发生什么。例如,如果您在没有自动换带器的情况下写入磁带,就会发生这种情况;当磁带填满时,在磁带被交换之前无法归档任何其他内容。您应该确保任何错误条件或对人工操作员的请求都被适当地报告,以便能够合理地快速解决问题。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.95中。
当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 没有内置机制来确定哪些备份仍然是恢复后续增量备份的基础。您必须自行跟踪完整备份和增量备份之间的关系,并确保在恢复后续增量备份时可能需要之前备份的情况下不要删除它们。
增量备份通常仅对数据库规模相对较大且数据中很大一部分不发生变化或仅缓慢变化的数据库才有意义。对于小型数据库,忽略增量备份的存在并简单地执行完整备份(更易于管理)更为简单。对于所有数据都发生大量修改的大型数据库,增量备份不会比完整备份小很多。
仅当重放从比其依赖的上一个备份的后续检查点开始时,增量备份才有可能。如果您在主服务器上执行增量备份,则此条件始终满足,因为每个备份都会触发一个新的检查点。在备用服务器上,重放从最新的重启点开始。因此,如果自上一个备份以来活动很少,则备用服务器的增量备份可能会失败,因为可能没有创建新的重启点。
您可以使用底层 API 执行基本备份,而不是使用 pg_basebackup 执行完整或增量基本备份。此过程比 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 会为““消失的源文件””返回单独的退出代码,您可以编写驱动程序脚本来接受此退出代码作为非错误情况。此外,如果在 tar 复制文件时文件被截断,某些版本的 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/
,则使用正确的权限重新创建它,并注意确保如果之前已将其设置为符号链接,则重新建立它为符号链接。
如果您在步骤 2 中保存了未归档的 WAL 段文件,请将它们复制到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 中包含的页面快照的数量。
如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。