26.4. 日志传送的替代方法

26.4.1. 实现
26.4.2. 基于记录的日志传送

前一节描述的内建后备模式的一种替代方案是使用一个轮询归档位置的restore_command。这是版本 8.4 及以下版本中唯一可用的选项。关于这种实现的一个参考请见pg_standby模块。

注意在这种模式中,服务器将一次应用一整个文件的 WAL,因此如果你使用后备服务器来查询(见热备),那么主服务器上的一个动作和后备服务器上该动作变得可见之间会有一个延迟,该延迟对应着填满 WAL 文件的时间。archive_timeout可以被用来缩短该延迟。还要注意你不能把流复制和这种方法组合起来使用。

在主服务器和后备服务器上都会发生的操作是通常的连续归档和恢复任务。两个数据库服务器之间唯一的接触点是两者共享的 WAL 文件归档:主服务器写这个归档,后备服务器读取这个归档。必须要小心地保证来自独立主服务器的 WAL 归档不会混合在一起或者混淆。如果归档只被后备操作需要,它不必很大。

使得两台松耦合的服务器一起工作的诀窍是在后备服务器上使用的restore_command,当要求下一个 WAL 文件时,会等待它在主服务器上变得可用。正常的恢复处理将从 WAL 归档请求一个文件,如果该文件不可用则会报告失败。对于后备处理来说下一个 WAL 文件不可用很正常,因此后备服务器必须等待它出现。对于以.backup.history结尾的文件没有必要等待,并且必须返回一个非零的返回码。一个等待的restore_command可以用一种习惯的脚本编写,在其中轮询下一个 WAL 文件的存在之后进行循环。也必须有某种方式来触发故障转移,那将打断restore_command:打破循环并返回一个文件未找到错误给后备服务器。这会结束恢复并且后备服务器将接下来变成一个正常的服务器。

一个合适的restore_command的伪代码是:

triggered = false;
while (!NextWALFileReady() && !triggered)
{
    sleep(100000L);         /* wait for ~0.1 sec */
    if (CheckForExternalTrigger())
        triggered = true;
}
if (!triggered)
        CopyWALFileForRecovery();

pg_standby模块中提供了一个等待的restore_command的工作例子。它也可被用作如何正确实现上述逻辑的参考。它也可以根据需要被扩展来支持指定的配置和环境。

触发故障转移的方法是规划和设计中的一个重要部分。一种潜在的选项是restore_command命令。它对每一个 WAL 文件被执行一次,但是运行restore_command的进程会为每一个文件创建和死亡,因此没有守护进程或服务器进程,并且也不能使用信号或信号句柄。因此,restore_command不适合于触发故障转移。可以使用一种简单的超时功能,特别是和主服务器上已知的archive_timeout设置一起。但是,由于一个网络问题或者繁忙的主服务器可能足以发起故障转移,这有点容易产生错误。如果可以安排,一种提醒机制(例如显式创建一个触发器文件)是最理想的。

26.4.1. 实现

使用这种替代方案配置一个后备服务器的简短过程如下所示。对于每一步的细节,可以参考之前的小节。

  1. 尽可能将主系统和后背系统设置成近乎一致,包括在同一发行级别上的两个相同的PostgreSQL拷贝。

  2. 在后备服务器上建立从主系统到一个 WAL 归档目录的连续归档。确保在主服务器上archive_modearchive_commandarchive_timeout被恰当地设置(见第 25.3.1 节)。

  3. 建立主服务器的一个基础备份(见第 25.3.2 节),并且把该数据载入到后备服务器。

  4. 在后备服务器上开始从本地 WAL 归档的恢复,按之前所述用restore_command等待(见第 25.3.4 节)。

恢复将 WAL 归档当作只读的来处理,因此一旦一个 WAL 文件已经被复制到后备系统,在它正在被后备数据库服务器读取时可以被同时复制到磁带。因此,可以在为了长期灾难恢复目的存储文件的同时运行一个用于高可用性的后备服务器。

为了测试的目的,可以在一个相同的系统上运行主服务器和后备服务器。这对于服务器鲁棒性并不会提供任何有意义的改进,对 HA 也一样。

26.4.2. 基于记录的日志传送

也可以使用这种替代方法来实现基于记录的日志传送,不过这需要定制开发,并且只有在一整个 WAL 文件被传送之后改变才会对热后备查询可见。

一个外部程序可以调用pg_walfile_name_offset()函数(见第 9.26 节)来找出 WAL 的当前末端的文件名和其中准确的字节偏移。它接着可以直接访问 WAL 文件并且将从上一个已知的 WAL 末尾到当前末尾之间的数据拷贝到后备服务器。通过这种方法,数据丢失的窗口是复制程序的轮询周期时间,这可以为非常小,并且不会有强制部分使用的段文件被归档所浪费的带宽。注意后备服务器的restore_command脚本只能处理整个 WAL 文件,因此增量复制的数据通常不会对后备服务器可用。只有当主服务器死掉时它才有用 — 那时最后一个部分 WAL 文件会在允许它发生之前被喂给后备服务器。这个处理的正确实现要求restore_command脚本和数据复制程序的合作。

PostgreSQL 版本 9.0 开始,你可以使用流复制(见第 26.2.5 节)来实现事半功倍的效果。