Postgresql管理系列-第十章 基礎備份和PITR(Point-in-Time Recovery)

       數據庫備份大概可以分爲兩類:邏輯備份和物理備份。它們兩者有長處也有短處,比如,邏輯備份需要花費大量的時間,特別是需要花費大量的時間備份大的數據庫,而且需要更多的時間來恢復數據庫。相反的,物理備份相對在較短的時間內備份和恢復數據庫,所以在實際系統中,物理備份是非常重要和有用的功能。


在postgresql中,在線物理全備份從8.0版本就有了,並且運行的整個數據庫集羣的快照作爲一個基礎備份
從8.0版本支持PITR, PITR是持續的歸檔功能創建的歸檔文件加上基礎備份用來恢復到數據庫集羣任何一個時間點的功能。例如,你犯了一個致命的錯誤(刪除了所有表),這個功能可以使數據庫恢復到你犯錯誤之前的那個時間點。

在這一章,將描述一下話題:

  • 基礎備份是什麼
  • PITR如何工作
  • timelineId是什麼
  • timeline history file是什麼

 

注意:在7.4版本或者更早,postgresql只支持邏輯備份(邏輯完全備份和部分備份)。

1.基礎備份

首先,使用低級命令備份的過程如下:

(1)發出pg_start_backup命令

(2)給數據庫做快照

(3)發出pg_stop_backup命令

這個很簡單的過程對於數據庫管理員來說很容易做到的,因爲它不需要特殊的工具,只需要常用的工具(比如copy命令或者類似的歸檔工具)來創建基礎備份,此外,在此過程中,沒有表鎖,並且所有用戶的發出的查詢都不會被備份操作影響。這一點要優於其他的開源數據庫。
做基礎備份更簡單的方法是可以使用pg_basebackup工具,但是它內部發出的也是這些低級命令。
這些命令是理解PITR的關鍵點之一,我們將在以下章節探索它們。

pg_start_backup和pg_stop_backup命令在這裏被定義: src/backend/access/transam/xlogfuncs.c.

Fig. 10.1. Making a base backup.

1.1 pg_start_backup


pg_start_backup準備進行基礎備份,正如9.8章描述的,恢復過程開始於一個REDO point,因此,pg_start_backup必須做檢查點,在開始基礎備份的時候明確的創建一個REDO點,此外,檢查點的位置必須保存在pg_control以外的文件中,因爲在備份過程中常規檢查點會多次發生。因此,pg_start_backup執行以下四個操作:


強制進入全頁寫模式
切換到當前WAL段文件(8.4版本以後).
做檢查點
創建一個備份標籤文件–這個文件創建在頂級目錄裏,包含了基礎備份必不可少的信息,比如檢查點位置 
第三步和第四步是這個命令的核心,第一步和第二步操作是爲了更可靠的恢復數據庫

備份標籤文件包含以下六個項目(11版本以後是7個項目:


CHECKPOINT LOCATION – 由此命令記錄的檢查點創建的LSN位置
START WAL LOCATION – 不和PITR一起使用, 但是會和流複製一起使用, 將在第11章詳細描述,被命名爲‘START WAL LOCATION’,因爲standby節點在流複製模式初始化的時候只讀取一次這個值。
BACKUP METHOD – 做基礎備份的方法(要麼'pg_start_backup' 要麼 'pg_basebackup'.)
BACKUP FROM – 顯示是從主庫還是備份備份
START TIME – pg_start_backup執行的時間戳
LABEL – pg_start_backup是指定的標籤
START TIMELINE – 備份開始的時間線,這是爲了進行健全性檢查,在11版本中已經引入

以下是9.6版本一個實際的例子:

postgres> cat /usr/local/pgsql/data/backup_label
START WAL LOCATION: 0/9000028 (file 000000010000000000000009)
CHECKPOINT LOCATION: 0/9000060
BACKUP METHOD: pg_start_backup
BACKUP FROM: master
START TIME: 2019-4-10 11:45:19 GMT
LABEL: Weekly Backup

你可以想象,當使用基礎備份恢復數據庫的時候,postgresql從backup_label文件中取出CHECKPOINT LOCATION,從相應的歸檔日誌中讀取檢查點記錄,然後,從記錄中獲取REDO點開始恢復

1.2 pg_stop_backup

pg_stop_backup執行以下五個操作來完成備份:

(1)如果已經由pg_start_backup強制改變了,那麼需要重置到non-full-page寫模式

(2)寫下備份結束的XLOG記錄

(3)切換wal文件

(4)創建一個備份歷史文件,這個文件包含backup_label文件的內容和pg_stop_backup執行的時間戳

(5)刪除backup_label文件,從基礎備份恢復需要backup_label文件,一旦copy了,在原始數據庫中就不需要了。

histroy file命名方法如下:
{WAL segment}.{基礎備份啓動時候的偏移值}.backup

 

2.PITR如何工作


下圖顯示了PITR的基礎概念,Postgresql在PITR模式下重放基礎備份下的歸檔wal數據,從pg_start_backup創建的REDO點到你要恢復的點,在postgresql中,要恢復的點稱爲恢復目標

Fig. 10.2. Basic concept of PITR.

這裏描述PITR如何工作。假設你在2019年4月10號12:05分執行一個錯誤操作。你應該刪除數據庫並且使用你之前的基礎備份恢復到一個全新的數據庫。然後,創建recovery.conf文件,並設置recovery_target_time參數,參數設置爲你錯誤操作的時間點,如下:

# 歸檔位置是/mnt/server/archivedir目錄.
restore_command = 'cp /mnt/server/archivedir/%f %p'
recovery_target_time = "2019-4-10 12:05 GMT"

數據庫啓動的時候,如果數據庫有recovery.conf和backup_label文件,將進入到PITR模式,
PITR過程幾乎和第九章描述的恢復過程一樣,唯一的不同有以下兩點:
(1)wal日誌或者歸檔日誌從哪裏讀?

  • 正常模式 –從基礎目錄下的pg_xlog子目錄讀取(10版本以後, 是pg_wal目錄)
  • PITR模式 – 從配置參數archive_command的歸檔目錄讀取.

(2)檢查點位置從哪裏讀取?

  • 正常模式 – 從pg_control文件讀取
  • PITR模式 – 從backup_label文件讀取.

PITR過程概述如下:

(1)爲了找到REDO點,postgresql使用內部函數read_backup_label讀取從backup_label取出的CHECKPOINT LOCATION的值。
(2)postgresql服務recovery.conf參數文件的值。比如restore_command和recovery_target_time
(3)postgresql 開始從REDO點重放wal數據,這個點可以從CHECKPOINT LOCATION輕鬆獲取。從歸檔日誌中讀取wal參數,通過執行參數restore_command中寫入的命令將歸檔從歸檔區域複製到臨時區域(複製到臨時區域的文件使用後會被刪除)
在這個例子中,postgresql從REDO點讀取並重放wal‘2019-4-10 12:05:00’之前的WAL數據,因爲參數recovery_target_time設置的是這個時間點,如果恢復目標沒有在recovery.conf中設置,postgreql將重放到歸檔日誌末尾。
(4)當恢復過程完成時,timeline history文件(比如‘00000002.history’)會被創建在pg_xlog子目錄下(10版本以後,在pg_wal子目錄下),如果歸檔開啓,則還會在歸檔目錄下創建同名的文件。以下章節將會介紹該文件。

提交和中止操作的記錄包含每個操作已完成的時間戳(兩個操作的XLOG數據部分分別在xl_xact_commit和xl_xact_abort中定義)。因此,如果將目標時間設置爲參數recovery_target_time,PostgreSQL可以選擇是否繼續恢復,只要它重放提交或中止操作的XLOG記錄。當重放每個動作的XLOG記錄時,PostgreSQL會比較目標時間和記錄中寫入的每個時間戳;如果時間戳超過目標時間,PITR過程將完成。

函數read_backup_label定義在src/backend/access/transam/xlog.c. 
xl_xact_commit 和xl_xact_abort定義在src/include/access/xact.h.

爲什麼我們可以使用通用歸檔工具進行基本備份?
恢復過程是使數據庫集羣處於一致狀態的過程,儘管集羣不一致。由於PITR基於恢復過程,即使基本備份是一堆不一致的文件,它也可以恢復數據庫集羣。這就是我們可以在沒有文件系統快照功能或特殊工具的情況下使用通用歸檔工具的原因。

3.timelienId和timeline歷史文件

PostgreSQL中的時間軸用於區分原始數據庫集羣和需要恢復到時間點的數據庫集羣,是PITR的核心概念。在本節中,描述了與時間線相關的兩件事:timelineId和timeline歷史文件


3.1 timelineId

每個時間線都給出一個相應的時間線Id,一個從1開始的4字節無符號整數。

爲每個數據庫集羣分配一個單獨的timelineId。 initdb創建的原始數據庫集羣的timelineId爲1.每當數據庫集羣恢復時,timelineId將增加1.例如,在上一節的示例中,從原始集羣恢復的集羣的timelineId爲2。

下圖從時間軸Id的角度說明了PITR過程。首先,我們刪除當前的數據庫集羣並用過去的基本備份進行恢復,以便返回到恢復的起始點,這種情況在圖中的紅色箭頭曲線中表示。接下來,我們啓動PostgreSQL服務器,它通過跟蹤初始時間軸(timelineId 1),將存檔日誌中的WAL數據從pg_start_backup創建的REDO點重放到恢復目標,並且這種情況在藍色箭頭行中表示。數字。然後,爲恢復的數據庫集羣分配新的timelineId 2,並在新的時間軸上運行PostgreSQL。

原始數據庫集羣和恢復數據庫集羣之間的timelineId關係

Fig. 10.3. Relation of  timelineId between an original and a recovered database clusters.

正如第9章中簡要提到的,WAL段文件名的前8位數等於爲每個段創建的數據庫集羣的timelineId。當timelineId改變時,WAL段文件名也將被改變。

着眼於WAL段文件,將再次描述恢復過程。假設我們使用兩個存檔日誌'000000010000000000000009'和'00000001000000000000000A'恢復數據庫集羣。新恢復的數據庫集羣被分配了timelineId 2,PostgreSQL從'00000002000000000000000A'創建了WAL段。下圖顯示了這種情況。

原始數據庫集羣和恢復數據庫集羣之間的WAL段文件的關係

Fig. 10.4. Relation of WAL segment files between an original and a recovered database clusters.

3.2 timeline歷史文件

當PITR進程完成時,會在歸檔目錄和pg_xlog子目錄(版本10或更高版本,pg_wal子目錄)下創建名稱爲“00000002.history”的時間軸歷史記錄文件。此文件記錄是從時間線分支出來的時間。

此文件的命名規則如下所示:

“8位數的新時間軸”.history


時間軸歷史文件至少包含一行,每行由以下三項組成:

timelineId - 用於恢復的存檔日誌的timelineId。
LSN - WAL段切換髮生的LSN位置。
原因 - 時間線改變的人類可讀性解釋


具體示例如下所示:

postgres> cat /home/postgres/archivelogs/00000002.history
1      0/A000198    before 2019-4-10 12:05:00.861324+00

含義如下:
數據庫集羣(timelineId = 2)基於timelineId爲1的基本備份,並在“2019-4-10 12:05:001.861324 + 00”之前的時間內通過重放歸檔檔日誌恢復到0 / A000198。
通過這種方式,每個時間軸歷史文件都會告訴我們各個恢復的數據庫集羣的完整歷史記錄。而且,它也用於PITR過程本身。詳細信息將在下一節中介紹。


時間線歷史文件格式在版本9.3中更改。版本9.3或更高版本及更早版本的格式如下所示,但不詳細說明。

Later version 9.3:
timelineId    LSN    "reason" 
Until version 9.2:
timelineId    WAL_segment    "reason"

4.使用timeline歷史文件進行PITR


timeline歷史文件在第二個和後續PITR過程中起着重要作用。通過嘗試第二次恢復,我們將探索如何使用它。
同樣,假設您在12:15:00在timelineId爲2的已恢復數據庫集羣中出錯。在這種情況下,要恢復數據庫集羣,您應該創建一個新的recovery.conf,如下所示:

restore_command = 'cp /mnt/server/archivedir/%f %p'
recovery_target_time = "2019-4-10 12:15:00 GMT"
recovery_target_timeline = 2

參數recovery_target_time設置您犯了新錯誤的時間,並且recovery_target_timeline設置爲'2',以便沿其時間線恢復。
重新啓動PostgreSQL服務器並進入PITR模式以在時間線Id 2的目標時間恢復數據庫。參見下圖

沿着timelineId 2在12:15:00恢復數據庫

Fig. 10.5. Recover the database at 12:15:00 along the timelineId 2.

(1)PostgreSQL從backup_label文件中讀取'CHECKPOINT LOCATION'的值。
(2)從recovery.conf中讀取一些參數值;在此示例中,restore_command,recovery_target_time和recovery_target_timeline。
(3)PostgreSQL讀取時間線歷史文件'00000002.history',該文件對應於參數recovery_target_timeline的值。
(4)PostgreSQL通過以下步驟重放WAL數據:

  •     從REDO點到寫在00000002.history文件中的LSN'0 / A000198'這個點,PostgreSQL讀取並重放時間軸Id爲1的相應存檔日誌的WAL數據。
  •     從LSN'0 / A000198'之後的那個點到時間戳'2019-4-10 12:15:00'之前的那個點,PostgreSQL讀取並重放時間軸Id爲2的相應的存檔日誌WAL數據。

(5)當恢復過程完成時,當前timelineId將前進到3,並在pg_xlog子目錄(在10以後的版本在pg_wal子目錄)和歸檔目錄中創建名爲00000003.history的新時間線歷史文件。


postgres> cat /home/postgres/archivelogs/00000003.history
1         0/A000198     before 2019-4-10 12:05:00.861324+00

2         0/B000078     before 2019-4-10 12:15:00.927133+00


當您多次執行PITR時,應明確設置timelineId以使用適當的時間軸歷史記錄文件。

這樣,時間軸歷史文件不僅是數據庫集羣的歷史日誌,還是PITR的恢復說明文檔。

參考:http://www.interdb.jp/pg/pgsql10.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章