PG中的时间线Timeline
Tags: PGPITRTimeline不完全恢复基于时间点的恢复备份恢复时间线
时间线Timeline概述
为了区分因数据库恢复造成的不同时间段的wal日志而产生的时间记录称为时间线(timeline)。当归档文件恢复完成后,会创建一个新的时间线用来区别新生成的WAL记录。
每当我们在数据库中完成一个事务时,所做的操作都会记录到$PGDATA/pg_wal目录下的wal日志文件中。WAL文件名由时间线和日志序号组成。
wal日志文件一般都是下面这种格式:
1 | 000000010000000000000001 |
当一个wal日志被写满后,便会创建新的wal日志000000010000000000000002,以此类推。
该文件中前8位,即:00000001表示的便是数据库的时间线。
1 2 3 4 5 6 7 8 9 10 | [postgres@xmmup archive]$ ll total 4 lrwxrwxrwx. 1 postgres postgres 69 Feb 17 22:51 000000010000000000000001 lrwxrwxrwx. 1 postgres postgres 69 Feb 17 22:51 000000010000000000000002 lrwxrwxrwx. 1 postgres postgres 69 Feb 17 22:51 000000010000000000000003 [postgres@xmmup archive]$ [postgres@xmmup archive]$ pg_controldata | grep TimeLineID Latest checkpoint's TimeLineID: 2 Latest checkpoint's PrevTimeLineID: 2 [postgres@xmmup archive]$ |
时间线ID号是WAL文件名组成之一,因此一个新的时间线不会覆盖由以前的时间线生成的WAL。
每个时间线类似一个分支,在当前时间线的操作不会对其他时间线WAL造成影响。
时间线就是为了让数据库管理员在数据库出现未知灾难时候依据基础备份和wal日志(包含已经归档的)恢复到宕机前的任意一个状态。
新生成时间线的情况(需要执行select pg_wal_replay_resume();
):
- 当对数据库进行了基于时间点的还原(PITR)后,就会产生一次新的时间线
- 当备库切换成主库也会产生一次时间线。
PG中通过timeline机制能够方便地实现数据库恢复到任意时间点,这对我们数据库备份有重要的作用。我们可以在数据库的使用中合理地备份和归档我们的数据,一旦数据出现丢失或损坏,我们都能有条不紊的使用timeline机制恢复出来我们需要的数据。
参数recovery_target_timeline
recovery_target_timeline ( string
)
指定恢复到特定时间轴。默认设置是沿着执行基本备份时的当前时间线恢复。将此设置为 latest 将恢复到存档中找到的最新时间轴,这在备用服务器中很有用。
recovery_target_timeline这个参数可以帮助我们将集群带入历史记录中的任何时间线,只要有效的基本备份和所有存档日志都到位。
除此之外,您只需要在复杂的重新恢复情况下设置此参数,您需要返回到在时间点恢复后到达的状态。
在pg中,当我们进行了基于时间点的还原(PITR)后,数据库会启用新的时间线并继续进行操作。
但是,当我们进行基于时间点的还原后如果发现又出现错误,想要继续还原数据库该如何操作呢?如何还原到原先旧的时间线呢?
我们可以使用recovery_target_timeline参数来指定数据库还原到某一个时间线上。
在通过pg_basebackup进行备份的时候添加参数“-R”就可以在备中自动产生recovery.conf文件,在这里就可以指定recovery_target_timeline=’’和recovery_target_time=’’参数来进行精准恢复了,而这里的recovery_target_timeline参数可以直接填写时间线产生的“历史文件”名字用来指定恢复到哪一条时间线上去。
1 2 3 4 5 6 7 8 9 10 11 | [postgres@xmmup pg_wal]$ ll total 114696 -rw-------. 1 postgres postgres 16777216 Feb 17 23:01 00000002000000000000000E -rw-------. 1 postgres postgres 16777216 Feb 17 22:56 00000002000000000000000F -rw-------. 1 postgres postgres 16777216 Feb 17 22:51 000000020000000000000010 -rw-------. 1 postgres postgres 16777216 Feb 17 22:51 000000020000000000000011 -rw-------. 1 postgres postgres 16777216 Feb 17 22:51 000000020000000000000012 -rw-------. 1 postgres postgres 16777216 Feb 17 22:51 000000020000000000000013 -rw-------. 1 postgres postgres 16777216 Feb 17 22:51 000000020000000000000014 -rw-------. 1 postgres postgres 50 Feb 17 22:56 00000002.history drwx------. 2 postgres postgres 88 Feb 17 22:56 archive_status |
当我们基于时间点的还原后,时间线便会加1,并创建一个名为NewTimelineID.history的新文件。00000002.history即为时间线产生的“历史文件”名字。
1 2 3 4 | [postgres@xmmup pgdata14]$ cat recovery.conf | grep recovery_target recovery_target_timeline='00000002.history' recovery_target_time='2022-02-17 22:50:00' [postgres@xmmup pgdata14]$ |
开启数据库之后通过读取归档日志就会将数据库恢复到’2022-02-17 22:50:00’这个时间点。
官方文档说明
将数据库恢复到以前的时间点的能力会产生一些类似于关于时间旅行和平行宇宙的科幻故事的复杂性。例如,在数据库的原始历史记录中,假设您在周二晚上 5:15 PM 删除了一个关键表,但直到周三中午才意识到自己的错误。毫不担心,您取出备份,恢复到周二晚上 5:14 PM 的时间点,然后开始运行。在这个数据库宇宙的历史,你从来没有删除过表。但是假设您后来意识到这不是一个好主意,并想回到原始历史中的某个星期三早上。如果在您的数据库启动并运行时,它会覆盖一些 WAL 段文件,这些文件会影响您现在希望可以返回的时间,那么您将无法做到这一点。因此,为避免这种情况,您需要将在执行时间点恢复后生成的一系列 WAL 记录与在原始数据库历史记录中生成的记录区分开来。
为了解决这个问题,PostgreSQL有一个时间线的概念. 每当归档恢复完成时,都会创建一个新的时间线来识别在该恢复之后生成的一系列 WAL 记录。时间线 ID 号是 WAL 段文件名的一部分,因此新时间线不会覆盖先前时间线生成的 WAL 数据。事实上,可以归档许多不同的时间线。虽然这似乎是一个无用的功能,但它通常是救命稻草。考虑一下您不太确定要恢复到哪个时间点的情况,因此必须通过反复试验进行多次时间点恢复,直到找到从旧历史分支的最佳位置。如果没有时间表,这个过程很快就会产生无法控制的混乱局面。使用时间线,您可以恢复到任何先前的状态,包括您之前放弃的时间线分支中的状态。
每次创建新的时间线时,PostgreSQL都会创建一个“时间线历史”文件,显示它从哪个时间线分支以及何时分支。当从包含多个时间线的存档中恢复时,这些历史文件是允许系统选择正确的 WAL 段文件所必需的。因此,它们就像 WAL 段文件一样被归档到 WAL 归档区。历史文件只是小文本文件,因此将它们无限期地保存起来既便宜又合适(与大的段文件不同)。如果愿意,您可以在历史文件中添加评论,以记录您自己关于如何以及为何创建此特定时间线的注释。当您通过实验获得大量不同的时间线时,此类评论将特别有价值。
恢复的默认行为是沿进行基本备份时的当前时间线进行恢复。如果您希望恢复到某个子时间线(即,您希望返回到恢复尝试后自身生成的某个状态),您需要在recovery.conf中指定目标时间线 ID 。您无法恢复到早于基本备份分支的时间线。
恢复失败的timeline排查
1、确认基础备份的时间属于哪条时间线。
2、确认归档或未归档wal日志是否存在。
3、确认recovery_target_time 指定的时间是正确的。
PITR示例
注意
1、在repmgr的高可用中,备库时间线timeline列的更新有延迟,需要在备库执行checkpoint后才会及时更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | [pg12@lhrpgcm1 pg_wal]$ repmgr cluster show ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string ----+----------+---------+-----------+----------+----------+----------+----------+--------------------------------------------------------- 1 | lhrpgcm1 | standby | running | lhrpgcm2 | default | 100 | 5 | host=192.168.0.11 user=repmgr port=5432 dbname=postgres 2 | lhrpgcm2 | primary | * running | | default | 100 | 6 | host=192.168.0.12 user=repmgr port=5432 dbname=postgres [pg12@lhrpgcm2 pg_wal]$ psql -p 5432 psql (12.9) Type "help" for help. postgres=# checkpoint; CHECKPOINT postgres=# exit [pg12@lhrpgcm1 pg_wal]$ repmgr cluster show ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string ----+----------+---------+-----------+----------+----------+----------+----------+--------------------------------------------------------- 1 | lhrpgcm1 | standby | running | lhrpgcm2 | default | 100 | 6 | host=192.168.0.11 user=repmgr port=5432 dbname=postgres 2 | lhrpgcm2 | primary | * running | | default | 100 | 6 | host=192.168.0.12 user=repmgr port=5432 dbname=postgres [pg12@lhrpgcm1 pg_wal]$ ll total 98328 -rw------- 1 pg12 pg12 41 Mar 9 10:52 00000002.history -rw------- 1 pg12 pg12 83 Mar 9 10:57 00000003.history -rw------- 1 pg12 pg12 125 Mar 9 11:06 00000004.history -rw------- 1 pg12 pg12 16777216 Mar 9 11:18 000000050000000000000004 -rw------- 1 pg12 pg12 167 Mar 9 11:13 00000005.history -rw------- 1 pg12 pg12 16777216 Mar 9 11:24 000000060000000000000004 -rw------- 1 pg12 pg12 16777216 Mar 9 11:13 000000060000000000000005 -rw------- 1 pg12 pg12 16777216 Mar 9 11:06 000000060000000000000006 -rw------- 1 pg12 pg12 16777216 Mar 9 11:17 000000060000000000000007 -rw------- 1 pg12 pg12 16777216 Mar 9 10:52 000000060000000000000008 -rw------- 1 pg12 pg12 209 Mar 9 11:18 00000006.history drwx------ 2 pg12 pg12 4096 Mar 9 11:18 archive_status |
每当我们进行基于时间点的还原后(做switchover或failover切换后),时间线便会加1,并创建一个名为NewTimelineID.history的新文件。
参考
http://postgres.cn/docs/13/continuous-archiving.html#BACKUP-TIMELINES
http://mysql.taobao.org/monthly/2015/07/03/
https://wiki.postgresql.org/images/e/e5/FOSDEM2013-Timelines.pdf
https://blog.csdn.net/weixin_39540651/article/details/111239341