在任何时间,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进行归档更高效,并且它们
将可以访问许多有用的服务器资源。有关归档模块的更多信息,请参见
第 51 章。
当存档命令被信号终止(除了SIGTERM被用作服务器关闭的一部分)或者由于shell出现退出状态大于125的错误(比如命令未找到),或者如果存档功能发出ERROR
或FATAL
,存档进程将中止并由postmaster重新启动。在这种情况下,失败不会在pg_stat_archiver中报告。
存档命令和库通常应设计为拒绝覆盖任何已存在的存档文件。这是一个重要的安全功能, 可以在管理员错误的情况下保持存档的完整性(例如将两个不同服务器的输出发送到同 一个存档目录)。
建议测试您提出的存档命令或库,以确保它确实不会覆盖现有文件,并且在这种情况下返回非零状态或false
。
上面的Unix示例命令通过包含一个单独的test
步骤来确保这一点。在某些Unix平台上,cp
具有诸如
-i
之类的开关,可以更简洁地执行相同的操作,但在未验证返回正确退出状态的情况下,不应依赖于这些功能。
(特别是,当使用-i
并且目标文件已经存在时,GNU cp
将返回状态零,这不是所需的行为。)
在设计存档设置时,请考虑如果存档命令或库重复失败会发生什么,因为某些方面需要操作员干预或存档空间不足。例如,如果您在没有自动更换器的情况下写入磁带,则当磁带填满时,直到更换磁带为止,将无法再进行存档。您应确保任何错误条件或对人类操作员的请求都能得到适当报告,以便情况能够相对快速地得到解决。直到情况得到解决之前,pg_wal/
目录将继续填充WAL段文件。(如果包含pg_wal/
的文件系统填满,PostgreSQL将执行紧急关闭。不会丢失已提交的事务,但数据库将保持离线状态,直到释放一些空间。)
归档命令或库的速度并不重要,只要它能跟上服务器生成WAL数据的平均速率即可。即使归档过程稍微落后,正常操作仍将继续。
如果归档严重落后,这将增加在灾难事件发生时可能丢失的数据量。这也意味着pg_wal/
目录将包含大量尚未归档的段文件,这可能最终超过可用的磁盘空间。建议您监视归档过程,以确保其按照您的意图工作。
在编写存档命令或库时,应假定要存档的文件名最长可达64个字符,并且可以包含任何组合的ASCII字母、数字和点号。
不需要保留原始相对路径(%p
),但需要保留文件名(%f
)。
请注意尽管 WAL 归档允许你恢复任何对你的PostgreSQL数据库中数据所做的修改, 但它不会恢复对配置文件的修改(即postgresql.conf
、pg_hba.conf
以及pg_ident.conf
),因为这些文件都是手工编辑的,而不是通过 SQL 操作来编辑的。 所以你可能会需要把你的配置文件放在一个日常文件系统备份过程可处理的位置。如何重定位配置文件请参阅第 20.2 节。
存档命令或函数仅在完成的WAL段上调用。因此,如果您的服务器生成的WAL流量很少(或者有间歇
期),在事务完成和安全记录到存档存储之间可能会有很长的延迟。为了限制未存档数据的
最旧时间,您可以设置archive_timeout,强制服务器至少在指定长的时间内切换
到新的WAL段文件。请注意,由于强制切换而提前存档的文件仍然与完全满文件相同长度。因此,
设置非常短的archive_timeout
是不明智的——它会使您的存档存储膨胀。
大约一分钟左右的archive_timeout
设置通常是合理的。
同样,如果你希望确保一个刚刚完成的事务能被尽快归档,可以使用pg_switch_wal
进行一次手动段切换。其他与WAL管理相关的使用函数在表 9.89中列出。
当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(见第 26.3.3 节)来制作一个基础备份。
没有必要关心创建一个基础备份所需的时间。但是,如果你正常地运行停用了full_page_writes
的服务器,你可能会注意到备份运行时的性能下降,因为full_page_writes
在备份模式期间会被实际强制实施。
要使用备份,你将需要保留所有在文件系统备份期间及之后生成的WAL段文件。为了便于你做这些,基础备份过程会创建一个备份历史文件,它将被立刻存储到WAL归档区域。该文件以文件系统备份中你需要的第一个WAL段文件命名。例如,如果开始的WAL文件是0000000100001234000055CD
,则备份历史文件将被命名为0000000100001234000055CD.007C9330.backup
.(文件名的第二部分表明WAL文件中的一个准确位置,一般可以被忽略)。一旦你已经安全地归档了文件系统备份和在备份过程中被使用的WAL段文件(如备份历史文件中所指定的) ,所有名字在数字上低于备份历史文件中记录值的已归档WAL段对于恢复文件系统备份就不再需要了,并且可以被删除。但是你应该考虑保持多个备份集以绝对保证你能恢复你的数据。
备份历史文件是一个很小的文本文件。它包含你指定给pg_basebackup的标签字符串,以及备份的起止时间以及起止WAL段。如果你使用该标签来标识相关转储文件,则已归档的历史文件足以说明需要哪个转储文件进行恢复。
由于你不得不保存最后一次基础备份之后的所有归档WAL文件,基础备份之间的间隔通常应该根据你希望在归档WAL文件上花费的存储空间来设定。你也应该考虑你准备花多长时间来进行恢复,如果需要恢复 — 系统将不得不重放所有那些WAL段,如果这些WAL段覆盖了最后一次基础备份以后的很长时间,重放过程将会花费一些时间。
使用低级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)。 在执行此操作时,无需停止数据库的正常运行。参见第 26.3.3.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,
以便在写入WAL的停止备份记录后立即使pg_backup_stop
返回。
默认情况下,pg_backup_stop
将等待直到所有WAL被归档,这可能需要一些时间。
必须谨慎使用此选项:如果WAL归档未正确监视,则备份可能不包括所有WAL文件,因此将是不完整的,无法恢复。
如果被拷贝的文件在拷贝过程中发生变化,某些文件系统备份工具会发出警告或错误。在建立一个活动数据库的基础备份时,这种情况是正常的,并非一个错误。然而,你需要确保你能够把它们和真正的错误区分开。例如,某些版本的rsync为“消失的源文件”返回一个独立的退出码,且你可以编写一个驱动脚本来将该退出码接受为一种非错误情况。同样,如果一个文件在被tar复制的过程中被截断,某些版本的GNU tar会返回一个与致命错误无法区分的错误代码。幸运的是,如果一个文件在备份期间被改变,版本为1.16及其后的GNU tar将会退出并返回1,而对于其他错误返回2。在版本1.23及其后的GNU tar中,你可以使用警告选项--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
子目录的内容,因为它可能包含在系统垮掉之前还未被归档的日志。
移除所有位于集簇数据目录和正在使用的表空间根目录下的文件和子目录。
从你的文件系统备份中恢复数据库文件。注意它们要使用正确的所有权恢复(数据库系统用户,不是root
!)并且使用正确的权限。如果你在使用表空间,你应该验证pg_tblspc/
中的符号链接被正确地恢复。
移除pg_wal/
中的任何文件,这些是来自于文件系统备份而不是当前日志,因此可以被忽略。如果你根本没有归档pg_wal/
,那么以正确的权限重建它。注意如果以前它是一个符号链接,请确保你也以同样的方式重建它。
如果你有在第2步中保存的未归档WAL段文件,把它们拷贝到pg_wal/
(最好是拷贝而不是移动它们,这样如果在开始恢复后出现问题你任然有未修改的文件)。
设定postgresql.conf
(见第 20.5.5 节)中的恢复配置设置,并且在集簇数据目录中创建一个recovery.signal
文件。你可能还想临时修改pg_hba.conf
来阻止普通用户在成功恢复之前连接。
启动服务器。服务器将会进入到恢复模式并且进而根据需要读取归档WAL文件。恢复可能因为一个外部错误而被终止,可以简单地重新启动服务器,这样它将继续恢复。恢复过程结束后,服务器将删除recovery.signal
(为了阻止以后意外地重新进入恢复模式),并且开始正常数据库操作。
检查数据库的内容来确保你已经恢复到了期望的状态。如果没有,返回到第1步。如果一切正常,通过恢复pg_hba.conf
为正常来允许用户连接。
所有这些的关键部分是设定一个恢复配置,它描述你希望如何恢复以及恢复要运行到什么程度。你绝对必须指定的是restore_command
,它告诉PostgreSQL如何获取归档WAL文件段。与archive_command
相似,这也是一个shell命令字符串。它可以包含%f
(将被期望的日志文件名替换)和%p
(将被日志文件被拷贝的目标路径名替换)。(路径名是相对于当前工作目录的,即集簇的数据目录)。如果你需要在命令中嵌入一个真正的%
字符,可以写成%%
。最简单的命令类似于:
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
文件的错误消息。这也是正常的并且不表示在简单恢复情
况中的问题,对此的讨论见第 26.3.5 节。
如果你希望恢复到之前的某个时间点(例如,恢复到幼稚的DBA丢弃了你主要的交易表之前),只需要 指定要求的停止点。你可以使用日期/时间、命名恢复点或一个 指定事务ID的结束时间来定义停止点(也被称为“恢复目标”)。在这种写法中,只有日期/时 间和命名恢复点选项非常有用,因为没有工具可以帮助你准确地确定要用哪个事务ID。
停止点必须在基本备份的结束时间之后,即pg_backup_stop
的结束时间。
不能使用基本备份来恢复到备份进行中的时间点。(要恢复到这样的时间点,必须返回到之前的基本备份并从那里继续向前滚动。)
如果恢复找到被破坏的WAL数据,恢复将会停止于该点并且服务器不会启动。在这种情况下,恢复进程需要从开头重新开始运行,并指定一个在损坏点之前的“恢复目标”以便恢复能够正常完成。如果恢复由于一个外部原因失败,例如一个系统崩溃或者WAL归档变为不可访问,则该次恢复可以被简单地重启并且它将会从几乎是上次失败的地方继续。恢复重启工作起来很像普通操作时的检查点:服务器周期性地强制把它的所有状态写到磁盘中,然后更新pg_control
文件来说明已经处理过的WAL数据,这样它们就不会被再次扫描。
将数据库恢复到一个之前的时间点的能力带来了一些复杂性,这和有关时间旅行和平行宇宙的科幻小说有些相似。例如,在数据库的最初历史中,假设你在周二晚上5:15时丢弃了一个关键表,但是一直到周三中午才意识到你的错误。不用苦恼,你取出你的备份,恢复到周二晚上5:14的时间点,并上线运行。在数据库宇宙的这个历史中,你从没有丢弃该表。但是假设你后来意识到这并非一个好主意,并且想回到最初历史中周三早上的某个时间。你没法这样做,在你的数据库在线运行期间,它重写了某些WAL段文件,而这些文件本来可以将你引向你希望回到的时间。因此,为了避免出现这种状况,你需要将完成时间点恢复后生成的WAL记录序列与初始数据库历史中产生的WAL记录序列区分开来。
要解决这个问题,PostgreSQL有一个时间线概念。无论何时当一次归档恢复完成,一个新的时间线被创建来标识恢复之后生成的WAL记录序列。时间线ID号是WAL段文件名的一部分,因此一个新的时间线不会重写由之前的时间线生成的WAL数据。实际上可以归档很多不同的时间线。虽然这可能看起来是一个无用的特性,但是它常常扮演救命稻草的角色。考虑到你不太确定需要恢复到哪个时间点的情况,你可能不得不做多次时间点恢复尝试和错误,直到最终找到从旧历史中分支出去的最佳位置。如果没有时间线,该处理将会很快生成一堆不可管理的混乱。而有了时间线,你可以恢复到任何之前的状态,包括早先被你放弃的时间线分支中的状态。
每次当一个新的时间线被创建,PostgreSQL会创建一个“时间线历史”文件,它显示了新时间线是什么时候从哪个时间线分支出来的。系统在从一个包含多个时间线的归档中恢复时,这些历史文件对于允许系统选取正确的WAL段文件非常必要。因此,和WAL段文件相似,它们也要被归档到WAL归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。如果你喜欢,你可以在一个历史文件中增加注释来记录如何和为什么要创建该时间线。当你由于试验的结果拥有了一大堆错综复杂的不同时间线时,这种注释将会特别有价值。
恢复的默认行为是沿着归档中所发现的最新的时间线进行恢复。如果你希望恢复到执行基础备份时的当前时间线或者某个指定的子时间线(即,你希望回到在一次恢复尝试后产生的某个状态),你需要指定current
或者在recovery_target_timeline中指定目标时间线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格式相当庞大,因为它包括了很多磁盘页快照。这些页快照被设计用于支持崩溃恢复,因为我们可能需要修复断裂的磁盘页。依靠你的系统硬件和软件,页断裂的风险可能会小到可以忽略,在此种情况下你可以通过使用full_page_writes参数关闭页快照来显著降低归档日志的总容量(在这样做之前阅读第 30 章中的注解和警告)。关闭页快照并不会阻止使用日志进行PITR操作。一个未来的开发点是通过移除不需要的页拷贝来压缩归档的WAL数据,即使full_page_writes
为on。同时,管理员可能希望通过尽可能增大检查点间隔参数来减少WAL中包含的页快照数量。