標籤:
“時間軸”(Timeline)是PG一個很有特色的概念,在備份恢複方面的文檔裡面時有出現。但針對這個概念的詳細解釋卻很少,也讓人不太好理解,我們在此仔細解析一下。
時間軸的引入
為了理解引入時間軸的背景,我們來分析一下,如果沒有時間軸,會有什麼問題?先舉個將資料庫恢複到以前時間點的例子。假設在一個資料庫的運行過程 中,DBA在周三12:00AM刪掉了一個關鍵的表,但是直到周五中午才發現這個問題。這個時候DBA拿出最初的Database Backup,加上存在歸檔目錄的日誌文 件,將資料庫恢複到周三11:00AM的時間點,這樣就能正常啟動和運行。但是,DBA後來意識到這樣恢複是不對的,想恢複到周四8:00AM的資料,這 時會發現無法做到:因為在資料庫不斷運行中,會產生與舊的WAL檔案重名的檔案,這些檔案進入歸檔目錄時,會覆蓋原來的舊日誌,導致恢複資料庫需要的 WAL檔案丟失。為了避免這種情況,需要區分未經處理資料庫曆史產生的WAL檔案和完成恢複之後繼續運行產生的(重名的)新WAL檔案。整個過程1所示:
為瞭解決這個問題,PostgreSQL引入了時間軸的概念。每當歸檔檔案恢複完成後,建立一個新的時間軸用來區別新產生的WAL記錄。WAL檔案名稱由時間軸和日誌序號組成,源碼實現如下:
#define XLogFileName(fname, tli, log, seg) \ snprintf(fname, XLOG_DATA_FNAME_LEN + 1, "%08X%08X%08X", tli, log, seg)
例如:
$ ls -100000002.history00000003.history00000003000000000000001A00000003000000000000001B
時間軸ID號是WAL檔案名稱組成之一,因此一個新的時間軸不會覆蓋由以前的時間軸產生的WAL。2所示,每個時間軸類似一個分支,在目前時間線的操作不會對其他時間軸WAL造成影響,有了時間軸,我們就可以恢複到之前的任何時間點。
What happens at a end of recovery?
- End of recovery means the point where the database opens up for writing
- New timeline is chosen
- A timeline history file is written
- The partial last WAL file on the previous timeline is copied with the new timeline‘s ID
- A checkpoint record is written on the new timeline
Example: End of recovery
LOG: database system was interrupted; last known up at 2013-01-30 21:45:14 EETLOG: starting archive recoveryLOG: redo starts at 13/E00000C8LOG: could not open file "pg_xlog/0000000100000013000000E4": No such file or directoryLOG: redo done at 13/E3D389A0LOG: last completed transaction was at log time 2013-01-30 21:45:20+02LOG: selected new timeline ID: 2LOG: archive recovery completeLOG: database system is ready to accept connections
First WAL file with new timeline
Timeline history file
0000000100000013000000E10000000100000013000000E20000000100000013000000E30000000100000013000000E40000000100000013000000E500000002.history0000000200000013000000E30000000200000013000000E40000000200000013000000E5
Timeline history file
新時間軸的出現情境
新的時間軸會在什麼情況下出現呢?
1、即時恢複(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
,不能恢複到早於基本備份分支的時間點。
2、standby promote
搭建一個PG主備,然後停止主庫,在備庫機器執行:
$ pg_ctl promote –D $PGDATA
這時候備庫將會升為主備,同時產生一個新的timeline,同樣產生一個新的history檔案。
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.history1 0/140000C8 no recovery target specified2 0/19000060 no recovery target specified3 0/1F000090 no recovery target specified
當資料庫在從包含多個時間軸的歸檔中恢複時,這些history檔案允許系統選取正確的WAL檔案,當然,它也能像WAL檔案一樣被歸檔到WAL歸檔目錄裡。曆史檔案只是很小的文字檔,所以儲存它們的代價很小。
當我們在recovery.conf指定目標時間軸tli進行恢複時,程式首先尋找.history檔案,根據.history檔案裡面記錄的時間軸分支關係,找到從pg_control裡面的startTLI到tli之間的所有時間軸對應的記錄檔,再進行恢複。
總結
PG中通過timeline機制能夠方便地實現資料庫恢複到任意時間點,這對我們Database Backup有重要的作用。我們可以在資料庫的使用中合理地備份和歸檔我們的資料,一旦資料出現丟失或損壞,我們都能有條不紊的使用timeline機制恢複出來我們需要的資料。
參考:
http://mysql.taobao.org/monthly/2015/07/03/
https://wiki.postgresql.org/images/e/e5/FOSDEM2013-Timelines.pdf
postgreSQL 時間軸