最近遇到这样一个需求:在做时间点恢复时,需要从主库获取最近生成的那些xlog文件(需要获取的xlog文件名是已知的)。怎么办?一个想法是,利用scp等工具,直接从主库下载,这要求我们处理整个下载过程,比较麻烦。其实PG已经为我们准备了一个xlog传输工具——pg_receivexlog。这个工具可能很多人都没注意到,而且官方文档中介绍的很少。在这里我们为大家解析一下这个工具。

能做什么

pg_receivexlog能为我们做什么呢?它能够从一个PG服务器,获取你想要的那些xlog日志文件。初步研究后,我们可以得到以下信息:

  1. 它以类似流式复制(streaming replication)的方式,获取主库的xlog文件。这意味着你要以超级用户或有replication权限的用户,连接PG进行日志传输,且要在pg_hba.conf里面,对其做权限配置。在连接建立后,PG服务器会有一个独立的WAL sender进程,负责xlog的传输,所以max_wal_senders要至少为1,使我们能获得一个WAL sender。
  2. 它不会等待一个xlog文件写完后才开始传输。也就是说,正在被写的xlog文件,也会进行传输,因此可以通过这个工具实时获取最新的xlog内容。
  3. 可以使用replication slot,通过同步replication slot的方式进行日志传输。这样做的好处是,主库在xlog传输完成前不会删除xlog文件。不过可能的风险是,如果日志没有利用slot成功传输,可能导致日志堆积在PG里面,最终把磁盘占满。

如何启动

PG安装后的bin目录里面,一般包含了pg_receivexlog这个工具。可以使用下面的方式启动它:

  1. pg_receivexlog -h <host name> -p <port> -U <user> -W <password> -D <local dir to store xlog files>

其中,-h -p -U -W 选项指定要连接的PG的主机名、端口、用户、密码,-D 选项指定本地的一个目录,用于存储下载的xlog文件。另外缺省情况下,如果连接无法建立,或传输过程中连接意外断开,pg_receivexlog会进行重试,如果不想重试,可以指定-n选项。

有个问题是,如何指定要传输哪些xlog文件?先来看看pg_receivexlog如何确定从哪个xlog文件开始传输的。从src/bin/pg_basebackup/pg_receivexlog.c 的FindStreamingStart函数可以看出,pg_receivexlog会扫描整个-D选项指定的目录,将扫描到的每个文件名,去掉其timeline部分,转换为64为整数。选取其中对应整数最大的文件,按如下方式选择开始下载的文件:如果这个文件是以.partial为后缀的,则重新下载此文件和后续文件;如果该文件不带.partial后缀,是一个完整的日志文件,则从此文件的下一个文件(文件名加1)开始下载。如果我们需要从00000001000000000000001B到00000001000000000000001D的几个文件,则只需要在-D指定的目录里面执行:

  1. touch 00000001000000000000001B.partial

保证此目录没有其他文件,然后按上面列出的方式启动pg_receivexlog即可,pg_receivexlog会重新下载00000001000000000000001B和后续文件。

如何停止

如何停止pg_receivexlog的执行呢?pg_receivexlog已经下载了我们需要的文件后,并不会自动停止,我们也没有办法指定它下载到哪个文件结束。唯一的办法是通过Ctl-C命令向它发送SIGINT信号来结束它。类似的,可以直接向它的进程发生kill命令:

  1. kill -SIGINT <pg_receivexlog pid>

注意,pg_receivexlog只在成功传输完一个xlog文件后,才检查是否收到了SIGINT信号,因此你只可能在一个文件接收完成后正常结束pg_receivexlog运行。其实更暴力的办法是直接kill -9 也是可以的。

从上面的分析可以看出,pg_receivexlog这个工具还是比较简单易用的。除了传输xlog日志,可以利用它做一个日志服务器,用来存储归档的日志;还可以做为一主多备方案。由此可见,pg_receivexlog既是一个很实用的工具,也是一个可以用于更多场景的让人充满想象的利器。