除了前几节介绍的内置备库模式,也可以使用一个轮询归档位置的 restore_command。在 8.4 及更早版本中,这是唯一可用的方法。采用这种配置时,应关闭 standby_mode,因为备库运行所需的轮询由你自己实现。其参考实现参见 pg_standby 模块。
注意,在这种模式下,服务器每次应用一整个 WAL 文件。因此,如果使用备库处理查询(参见热备),主库上的操作与备库上能看到该操作的结果之间,会有一段延迟,其长度相当于写满一个 WAL 文件所需的时间。可以用 archive_timeout 缩短这一延迟。还要注意,这种方法不能与流复制结合使用。
主库和备库上执行的操作都是普通的连续归档和恢复任务。两台数据库服务器之间唯一的联系,就是它们共享的 WAL 文件归档:主库写入归档,备库从归档读取。必须确保不同主库的 WAL 归档不会混在一起或弄错。如果归档仅用于备库运行,则无需保留很大的归档。
让这两台松散耦合的服务器协同工作的关键,只是备库上的 restore_command:当请求下一个 WAL 文件时,它会等待主库提供该文件。restore_command 在备库的 recovery.conf 文件中指定。正常恢复处理会从 WAL 归档请求文件,如果文件不可用,就报告失败。对备库处理而言,下一个 WAL 文件尚不可用是正常情况,因此备库必须等待它出现。对于以 .history 结尾的文件,则无需等待,必须返回非零返回码。可以编写一个自定义脚本,循环检查下一个 WAL 文件是否存在,从而实现会等待的 restore_command。还必须提供触发故障切换的方法,用来中断 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 设置的情况下配合使用。不过,这容易出错,因为网络问题或主库繁忙就可能导致故障切换。如果能够安排,显式创建触发文件之类的通知机制是理想的方式。
使用这种替代方法配置备库的简要流程如下。各步骤的完整细节,参见所注明的前面章节。
尽可能将主库和备库系统配置得相同,包括安装两个完全相同、发行版本一致的 PostgreSQL 副本。
配置连续归档,将主库的 WAL 归档到备库上的一个目录。确保在主库上正确设置 archive_mode、archive_command 和 archive_timeout(参见 Section 25.3.1)。
制作主库的基础备份(参见 Section 25.3.2),并将这些数据装载到备库上。
在备库上从本地 WAL 归档开始恢复,在 recovery.conf 中指定前面所述的会等待的 restore_command(参见 Section 25.3.4)。
恢复过程将 WAL 归档视为只读,因此,WAL 文件一旦复制到备库系统,就可以在备库读取它的同时,将其复制到磁带上。这样,既能运行备库提供高可用,又能保存文件用于更长期的灾难恢复。
为了测试,可以在同一个系统上同时运行主库和备库。这不会对服务器的稳健性带来有意义的提升,也不能称为高可用。
也可以使用这种替代方法实现基于记录的日志传送,但需要自行开发,而且只有整个 WAL 文件传送完成后,更改才会对热备上的查询可见。
外部程序可以调用 pg_walfile_name_offset() 函数(参见 Section 9.26),取得当前 WAL 末尾所在的文件名及其在文件中的精确字节偏移。随后就可以直接访问 WAL 文件,将上次已知的 WAL 末尾到当前末尾之间的数据复制到备库。采用这种方法,可能丢失数据的时间窗口就是复制程序的轮询周期,可以很短,而且不会因为强制归档未写满的段文件而浪费带宽。注意,备库的 restore_command 脚本只能处理完整的 WAL 文件,因此这些增量复制的数据通常不会提供给备库使用。它们只有在主库失效时才有用 — 此时,在允许备库启动前,将最后一个不完整的 WAL 文件交给备库。要正确实现这一过程,restore_command 脚本必须与数据复制程序配合。
从 PostgreSQL 9.0 开始,可以使用流复制(参见 Section 26.2.5),更省力地获得同样的收益。