时间线概念
将数据库恢复到一个之前的时间点的能力带来了一些复杂性。例如,在数据库的最初历史中,假设你在周二晚上5:15时丢弃了一个关键表,但是一直到周三中午才意识到你的错误。不用苦恼,你取出你的备份,恢复到周二晚上5:14的时间点,并上线运行。在数据库宇宙的_这个_历史中,你从没有丢弃该表。但是假设你后来意识到这并非一个好主意,并且想回到最初历史中周三早上的某个时间。你没法这样做,在你的数据库在线运行期间,它重写了某些WAL段文件,而这些文件本来可以将你引向你希望回到的时间。因此,为了避免出现这种状况,你需要将完成时间点恢复后生成的WAL记录序列与初始数据库历史中产生的WAL记录序列区分开来。
解决这个问题,PostgreSQL有一个时间线的概念。无论何时当一次归档恢复完成,一个新的时间线被创建来标识恢复之后生成的WAL记录序列。时间线ID号是WAL段文件名的一部分,因此一个新的时间线不会重写由之前的时间线生成的WAL数据。实际上可以归档很多不同的时间线。虽然这可能看起来是一个无用的特性,但是它常常扮演救命稻草的角色。考虑到你不太确定需要恢复到哪个时间点的情况,你可能不得不做多次时间点恢复尝试和错误,直到最终找到从旧历史中分支出去的最佳位置。如果没有时间线,该处理将会很快生成一堆不可管理的混乱。而有了时间线,你可以恢复到_任何_之前的状态,包括早先被你放弃的时间线分支中的状态。
每次当一个新的时间线被创建,PostgreSQL会创建一个“时间线历史”文件,它显示了新时间线是什么时候从哪个时间线分支出来的。系统在从一个包含多个时间线的归档中恢复时,这些历史文件对于允许系统选取正确的WAL段文件非常必要。因此,和WAL段文件相似,它们也要被归档到WAL归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。
时间线案例
下图是一个PostgreSQL数据库的时间线,我们在当wal日志写到000000010000000000000005时,进行了一次完整的备份,接着再产生一些新的wal日志
我们想要把数据还原到000000010000000000000007这个点。因此我在postgresql.conf文件中将恢复目标lsn设置为“ 0/07000060”。接着进行还原,当我们还原之后,数据库切换到了新的时间线。
此时,PostgreSQL已在wal日志7处分支到新的时间线,并开始创建时间线ID为2的新wal日志。我们可以下wal日志目录下看到00000002.history文件。 该文件是可读文件,内容大致为:
1<parentTLI> 0/70000D8 <switchpoint> after LSN 0/7000060<reason>
parentTLI ID of the parent timeline
switchpoint XLogRecPtr of the WAL location where the switch happened
reason human-readable explanation of why the timeline was changed
这个时候,我在00000002000000000000000D的wal日志中执行了错误的操作,想要回退到时间线2的00000002000000000000000C处,那么我要如何操作呢,如果像前面一样只指定lsn那么怎么保证不会回退到时间线1中呢?
这个时候我们便可以通过指定recovery_target_timeline来实现。
在postgresql.conf文件中添加:
recovery_target_timeline = '2'
recovery_target_lsn = '0/0C000060'
此时可以看到新建了00000003.history文件,该文件内容如下:
-bash-4.1$ cat 00000003.history
1 0/70000D8 after LSN 0/7000060
2 0/C0000D8 after LSN 0/C000060
不难发现: history file这个文件中记录的就是这个时间线是从哪个WAL位置开始生成的。
下图为时间线切换点示意图,从图中可以看到,时间线2的第一条wal日志,会记录上一条时间线1的wal日志信息
参考
PostgreSQL时间线(timeline)和History File_postgresql timeline-CSDN博客
25.3. 连续归档和时间点恢复(PITR) (postgres.cn)
postgreSQL 时间线 - Still water run deep - 博客园 (cnblogs.com)