“时间线”(Timeline)是PG一个颇有特点的概念,在备份恢复方面的文档里面时有出现。但针对这个概念的详细解释却不多,也让人不太好理解,咱们在此仔细解析一下。mysql
为了理解引入时间线的背景,咱们来分析一下,若是没有时间线,会有什么问题?先举个将数据库恢复到之前时间点的例子。假设在一个数据库的运行过程 中,DBA在周三12:00AM删掉了一个关键的表,可是直到周五中午才发现这个问题。这个时候DBA拿出最初的数据库备份,加上存在归档目录的日志文 件,将数据库恢复到周三11:00AM的时间点,这样就能正常启动和运行。可是,DBA后来意识到这样恢复是不对的,想恢复到周四8:00AM的数据,这 时会发现没法作到:由于在数据库不断运行中,会产生与旧的WAL文件重名的文件,这些文件进入归档目录时,会覆盖原来的旧日志,致使恢复数据库须要的 WAL文件丢失。为了不这种状况,须要区分原始数据库历史生成的WAL文件和完成恢复以后继续运行产生的(重名的)新WAL文件。整个过程如图1所示:sql
为了解决这个问题,PostgreSQL引入了时间线的概念。每当归档文件恢复完成后,建立一个新的时间线用来区别新生成的WAL记录。WAL文件名由时间线和日志序号组成,源码实现以下:数据库
#define XLogFileName(fname, tli, log, seg) \ snprintf(fname, XLOG_DATA_FNAME_LEN + 1, "%08X%08X%08X", tli, log, seg)
例如:app
$ ls -1 00000002.history 00000003.history 00000003000000000000001A 00000003000000000000001B
时间线ID号是WAL文件名组成之一,所以一个新的时间线不会覆盖由之前的时间线生成的WAL。如图2所示,每一个时间线相似一个分支,在当前时间线的操做不会对其余时间线WAL形成影响,有了时间线,咱们就能够恢复到以前的任什么时候间点。post
What happens at a end of recovery?spa
Example: End of recovery3d
LOG: database system was interrupted; last known up at 2013-01-30 21:45:14 EET LOG: starting archive recovery LOG: redo starts at 13/E00000C8 LOG: could not open file "pg_xlog/0000000100000013000000E4": No such file or directory LOG: redo done at 13/E3D389A0 LOG: last completed transaction was at log time 2013-01-30 21:45:20+02 LOG: selected new timeline ID: 2 LOG: archive recovery complete LOG: database system is ready to accept connections
First WAL file with new timelinerest
Timeline history file日志
0000000100000013000000E1 0000000100000013000000E2 0000000100000013000000E3 0000000100000013000000E4 0000000100000013000000E5 00000002.history 0000000200000013000000E3 0000000200000013000000E4 0000000200000013000000E5
Timeline history filepostgresql
新的时间线会在什么状况下出现呢?
一、即时恢复(PITR)
配置recovery.conf文件:
restore_command = 'cp /mnt/server/archivedir/%f %p' //从归档目录恢复日志 recovery_target_time = '2015-7-16 12:00:00 ' //指定归档时间点,如没指定恢复到故障前的最后一完成的事务 recovery_target_timeline = 'latest' //指定归档时间线,’latest’表明最新的时间线分支,如没指定恢复到故障前的pg_control里面的时间线 standby_mode = ‘off’ //打开后将会以备库身份启动,而不是即时恢复
设置好recovery.conf文件后,启动数据库,将会产生新的timeline,并且会生成一个新的history文件。恢复的默认行为是沿着与当前基本备份相同的时间线恢复。若是你想恢复到某些时间线,你须要指定的recovery.conf目标时间线recovery_target_timeline
,不能恢复到早于基本备份分支的时间点。
二、standby promote
搭建一个PG主备,而后中止主库,在备库机器执行:
$ pg_ctl promote –D $PGDATA
这时候备库将会升为主备,同时产生一个新的timeline,一样生成一个新的history文件。
每次建立一个新的时间线,PostgreSQL都会建立一个“时间线历史”文件,文件名相似.history,它里面的内容是 由原时间线history文件的内容再追加一条当前时间线切换记录。假设数据库恢复启动后,切换到新的时间线ID=5,那么文件名就是 00000005.history ,该文件记录了本身从什么时间哪一个时间线什么缘由分出来的,该文件可能含有多行记录,每一个记录的内容格式以下:
* <parentTLI> <switchpoint> <reason> * * parentTLI ID of the parent timeline * switchpoint XLogRecPtr of the WAL position where the switch happened * reason human-readable explanation of why the timeline was changed
例如:
$ cat 00000004.history 1 0/140000C8 no recovery target specified 2 0/19000060 no recovery target specified 3 0/1F000090 no recovery target specified
当数据库在从包含多个时间线的归档中恢复时,这些history文件容许系统选取正确的WAL文件,固然,它也能像WAL文件同样被归档到WAL归档目录里。历史文件只是很小的文本文件,因此保存它们的代价很小。
当咱们在recovery.conf指定目标时间线tli进行恢复时,程序首先寻找.history文件,根据.history文件里面记录的时间线分支关系,找到从pg_control里面的startTLI到tli之间的全部时间线对应的日志文件,再进行恢复。
PG中经过timeline机制可以方便地实现数据库恢复到任意时间点,这对咱们数据库备份有重要的做用。咱们能够在数据库的使用中合理地备份和归档咱们的数据,一旦数据出现丢失或损坏,咱们都能有条不紊的使用timeline机制恢复出来咱们须要的数据。
参考:
http://mysql.taobao.org/monthly/2015/07/03/
https://wiki.postgresql.org/images/e/e5/FOSDEM2013-Timelines.pdf