來自: http://zisedeqing.blog.163.com/blog/static/95550871201481115942717/、
1.1 基本原理
正常情況下,資料庫是沿着一條時間線一直延伸的,但是如果中途,使用者期望從歸檔中進行恢複,則這時資料庫的時間線就會産生分支,沿着新的時間線延伸。如下圖所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuYDM4gDO3QjNzYTN3kzM5cDNyMzLc1TP3p0YPhUeWZTcNVnewYERuxETnpFbu9CX0VmbuYjMx4Caw5CMn1Wavw1LcpDc0RHaiojIsJye.png)
1.2 基本流程
使用時間線進行恢複的基本流程是:
1. 确定recoveryTargetTLI
即要恢複到的那個時間線
2. 确定時間線集合expectedTLIs
3. Redo
根據expectedTLIs,确定正确的WAL檔案
4. Redo結束,确定新的時間線
下面分别介紹這幾部中在PG中是如何實作的。
1.3 實作
1.3.1 時間線的表示
使用TimeLineID表示一個時間線,實際上就是一個無符号的整型。時間線從1開始,然後依次遞增。
1.3.2 産生新的時間線
1. 新時間線産生的時機
隻有在啟動時,從歸檔中進行恢複,才會産生新的時間線,否則一直沿着原來的時間線走。
2. History檔案
在産生新的時間線時,會建立一個曆史檔案,叫做history檔案:
? 命名規則:
NewTimeLine.history
? 内容:
父親時間線|分出時的日志檔案名|分出的原因
? 作用:
在歸檔恢複時,如果該歸檔中包含多個時間線,則可以幫助系統在恢複時找到正确的WAL檔案。
? 生命周期:
每個history檔案,在建立新的時間線時會被删除,但是其内容則會copy到新的history檔案的開頭。如下所示:
00000002.history的内容如下:
則00000003.history的内容如下:
? 歸檔
History檔案在産生會,會“立即”進行歸檔,是以在歸檔目錄中會存在完整的時間線曆史檔案的序列。
1.3.3 恢複期間的時間線
在資料庫正常運作期間,時間線是不會發生變化的,隻有在歸檔恢複時才會發生時間線的變化,下面說明在恢複期間時間線時如何變化,以及如何使用時間線恢複到正确的位置。
1.3.3.1時間線的确定
恢複期間時間線的選擇有如下的幾種情況:
1. 從控制檔案裡面記錄的checkpoint記錄得到時間線:
recoveryTargetTLI =ControlFile->checkPointCopy.ThisTimeLineID;
2. 從recovery.conf中讀取使用者配置的時間線
a) 如果使用者沒有設定時間線,則時間線不變;
b) 如果使用者設定的時間線為0,則表示使用者期望回複到最新的時間線
确定最新時間線的方法是:
從recoveryTargetTLI記錄的時間線開始,這個掃描history檔案,直到找到不存在history檔案的那個時間線。
c) 如果使用者設定的時間線大于 0 ,則使用該時間線;
确定好恢複時要恢複到的時間線後,我們需求驗證該時間線的有效性:
判斷是否存在history檔案,如果不存在,則是無效的時間線,系統退出;
時間線為1的時間線是沒有history檔案的,因為它沒有parent時間線。
1.3.3.2時間線的使用
1. 使用history檔案确定expectedTLIs
a) expectedTLIs是恢複期間可能需要掃描的時間線的集合,它記錄的在恢複期間可能的會使用到的WAL檔案所在的時間線。
b) 掃描history檔案,把history檔案中的每個parent時間線添加到expectedTLIs連結清單頭部,最後把recoveryTargetTLI加到連結清單頭部
2. 使用expectedTLIs
a) WAL日志檔案的名字是由TLI+logid+segment組成的,是以必須找到正确的時間線才能選擇正确的WAL檔案;
b) 找到正确的WAL檔案
i. 根據recptr,計算logid和segno
ii. 從前往後周遊expectedTLIs連結清單
根據每個時間線,拼成WAL檔案名,然後試圖打開該檔案,如果檔案不存在,則繼續周遊,直到找到存在的檔案
iii. 如果沒有找到WAL檔案,則報錯
c) 對于logid和segno相同的WAL檔案
i. 通過b),找到正确的WAL檔案
ii. 對于logid和segno相同的WAL檔案,其TLI必然不同,我們選擇在expectedTLIs連結清單位置靠前的那個時間線上的WAL檔案,這樣做的原因是:
u 恢複必然從某個checkpoint日志開始;
u 而恢複開始的checkpoint日志必然在TLI大的那個WAL檔案内,原因是:
l 日志redo完成後,我們是先建立新的時間線,然後在請求做checkpoint。
u 是以checkpoint之後的日志也必然在TLI大的那個WAL檔案内。
3. 檔案源的選擇
a) 預設是從XLOG_FROM_PG_XLOG裡面,如果是歸檔恢複,則在加上XLOG_FROM_ARCHIVE
b) 在選擇WAL檔案時,先從歸檔裡面找,如果找不到,再從pg_xlog裡面找
c) 如果都沒有找到,則報錯
4. 恢複完成後新時間線的建立
a) 歸檔恢複後,我們選擇建立新的時間線,原因:
i. 本次恢複後,産生的日志檔案都在新的時間線上,不會覆寫就的時間先上的日志;
ii. 如果發現本次恢複不是想要的結果,則可以再次直到恢複的時間線,不會由于日志覆寫該導緻恢複失敗;
b) 确定新的時間線
i. 從recoveryTargetTLI往後找,直到找到不存在history的時間線;
ii. 然後對該時間線加1,就是本次恢複後的新的時間線
u 是以,即使我們恢複到之前的時間線,也不會導緻時間線不惟一;
u +1的原因是,不存在history的那個時間先應該是歸檔恢複之前使用的目前的時間線,是以需要加1;
5. Redo的結束
a) 在隻設定了TLI的情況下,redo完recoveryTargetTLI的日志後,redo操作結束;
結束方式:
在讀取下一條日志時,如果在expectedTLIs内找不到适當的WAL檔案,則終止redo
b) 在設定了TLI時,redo的終止點隻會比TLI的時間點早,而不會比它晚,原因是redo需要的日志檔案必須在expectedTLIs内。
---------------
-rw------- 1 wln wln 16777216 07-12 10:30 000000020000000000000019
-rw------- 1 wln wln 16777216 07-07 15:41 00000002000000000000001A
-rw------- 1 wln wln 41 07-06 08:41 00000002.history
-rw------- 1 wln wln 16777216 07-12 10:31 000000030000000000000019
-rw------- 1 wln wln 16777216 07-12 10:31 00000003000000000000001A
-rw------- 1 wln wln 84 07-12 10:31 00000003.history
-rw------- 1 wln wln 16777216 07-12 12:49 000000040000000000000019
-rw------- 1 wln wln 16777216 07-12 10:39 00000004000000000000001A
-rw------- 1 wln wln 127 07-12 10:38 00000004.history
drwx------ 2 wln wln 4096 07-12 10:38 archive_status
[[email protected] pg_xlog]$ cat 00000002.history
1 0/602445C no recovery target specified
[[email protected] pg_xlog]$ cat 00000003.history
1 0/602445C no recovery target specified
2 0/19FBD5DC no recovery target specified
[[email protected] pg_xlog]$ cat 00000004.history
1 0/602445C no recovery target specified
2 0/19FBD5DC no recovery target specified
3 0/19FBD6FC no recovery target specified
http://mysql.taobao.org/monthly/2015/07/03/