引言
在进行PostgreSQL数据恢复时,常常会遇到一个棘手的情况:用户 pg_wal 目录下的 WAL 文件不完整,并且没有配置归档。按常规思路,数据恢复似乎已经无望。但是,先别急着放弃!如果你及时备份了 pg_wal 目录,事情或许还有转机。
破题:WAL文件去哪了?
我们都知道,为了提升刷写 WAL 日志的效率,PostgreSQL 采用了一种机制来回收并复用已经不再使用的 WAL 段文件。简单来说,就是将一个旧的 WAL 段文件重命名为一个未来的 WAL 文件名。
这就能解释一个常见的现象:你可能会看到一个 WAL 段文件的时间戳是 12:00:00,而一个 LSN 值比它更大的 WAL 文件,时间戳却是 11:00:00。
所以,你以为“缺失”的那些 WAL 文件,很可能只是换了个马甲,正静静地等待被重新使用。我们恢复数据的关键,就在于找出这些被重命名的“未来” WAL 文件,并把它们的名字改回正确的序列,以供恢复工具识别。
在经历了多次手把手教用户手动重命名 WAL 文件后,我决定将这个功能单独抽离出来,形成一个自动化工具。今天正好有用户在恢复数据时用到了它,便写下这篇博客,分享一下 waltakeback 工具的使用方法。
waltakeback 使用方法
waltakeback 是 WalMiner 工具集中的一个子命令,专门用于找回并重命名被复用的 WAL 文件。我们先来看看它的帮助信息:
lchch@deepin:~$ walminer help waltakeback
walminer [command] [options]
COMMANDS
---------
#waltakeback
options
-D dic file for wal
-w source wal file path
-W target wal file path
-A copy all wal files
---------
#################################################
lchch@deepin:~$
参数说明:
-D:指定 WalMiner 的数据字典文件路径,这是解码和识别 WAL 所必需的。
-w:指定源 WAL 文件所在的目录,通常是你备份出来的 pg_wal 目录。
-W:指定目标目录,改名后的正确 WAL 文件将被复制或移动到这里。
-A:这是一个可选参数。如果启用,即使某个文件没有被重命名(即它已经在正确的位置上),也会被拷贝到 -W 指定的目标目录。
waltakeback 使用演示
使用工具之前的目录结构
假设我们有一个数据恢复场景,在 wal_old 目录中存放着备份的 WAL 文件。
lchch@deepin:~/Desktop/大事务多toast数据$ tree
.
├── wal
├── walminer.dic
└── wal_old
├── 000000010000000000000078
├── 000000010000000000000079
....
├── 0000000100000000000000AB
└── 0000000100000000000000AC
当我们用 WalMiner 对 wal_old 目录进行解码时,解码到 000000010000000000000078 文件后就停止了,不会继续解码 79 文件。这是因为 WalMiner 在 78 文件中读到了最后一个有效的 WAL 记录。
直接尝试读取 79 文件也不行,因为读取 WAL 文件时会根据文件名信息进行 checksum 校验,文件名不匹配会导致校验失败,从而无法解码。这意味着,79 及之后的一系列文件可能并不是它们名字所代表的位置。
使用 waltakeback 工具
这时,waltakeback 就派上用场了。我们运行以下命令:
lchch@deepin:~/Desktop/大事务多toast数据$ walminer waltakeback -D walminer.dic -w wal_old/ -W wal -A
#################################################
Walminer for PostgreSQL wal
Contact Author by mail 'lchch1990@sina.cn'
Vip License for fengxing
#################################################
COPY [/home/lchch/Desktop/大事务多toast数据/wal_old/000000010000000000000078] to [/home/lchch/Desktop/大事务多toast数据/wal/000000010000000000000078]
COPY [/home/lchch/Desktop/大事务多toast数据/wal_old/000000010000000000000079] to [/home/lchch/Desktop/大事务多toast数据/wal/000000010000000000000044]
......
COPY [/home/lchch/Desktop/大事务多toast数据/wal_old/0000000100000000000000AA] to [/home/lchch/Desktop/大事务多toast数据/wal/000000010000000000000075]
COPY [/home/lchch/Desktop/大事务多toast数据/wal_old/0000000100000000000000AB] to [/home/lchch/Desktop/大事务多toast数据/wal/000000010000000000000076]
COPY [/home/lchch/Desktop/大事务多toast数据/wal_old/0000000100000000000000AC] to [/home/lchch/Desktop/大事务多toast数据/wal/000000010000000000000077]
lchch@deepin:~/Desktop/大事务多toast数据$
从输出结果可以清晰地看到,工具不仅将文件从 wal_old 拷贝到了 wal 目录,还根据其内部状态自主判断并执行了重命名。例如,源文件 79 被重命名为 44 后放到了目标目录。

通过 waltakeback,我们成功“召回”了大量被复用改名而隐藏起来的历史 WAL 文件。这意味着,如果你的 pg_wal 目录备份得足够及时,有很大概率可以仅凭这个目录和对应的数据字典,就把丢失的数据找回来。
后记
至此,你的 PostgreSQL 数据恢复工具箱里又多了 waltakeback 这样一件利器。它在 WAL 文件不连续、看似缺失的绝境中,为你开辟了一条新的路径。

希望这个案例和工具能对你有帮助。在数据安全的道路上,多一份准备,就少一份风险。
