PostgreSQL管理—持續存檔和時間點恢復 (PITR)
持續存檔和時間點恢復 (PITR)
PostgreSQL在任何時候都在集群數據目錄的子目錄中維護一個預寫日志(WAL) 。pg_wal/日志記錄對數據庫數據文件所做的每一次更改。該日志的存在主要是出于安全的目的:如果系統崩潰,通過“重放”自上次檢查點以來創建的日志條目,可以將數據庫恢復到一致性。然而,日志的存在使得使用第三種策略備份數據庫成為可能:我們可以將文件系統級備份與WAL文件的備份結合起來。如果需要恢復,我們將恢復文件系統備份,然后從備份的WAL文件中重放,使系統恢復到當前狀態。與之前的兩種方法相比,這種方法的管理更加復雜,但它有一些顯著的好處:
- 我們不需要一個完全一致的文件系統備份作為起點。備份中的任何內部不一致都將通過日志重放來糾正(這與崩潰恢復期間發生的情況沒有明顯不同)。所以我們不需要文件系統快照功能,只需要tar或類似的歸檔工具。
- 由于我們可以將無限長的WAL文件序列組合起來進行重放,因此只需繼續歸檔 WAL 文件即可實現連續備份。這對于大型數據庫尤其有用,因為在這些數據庫中可能不方便經常性的進行完整備份。
- 沒有必要一直回放 WAL 條目。我們可以在任何時候停止重播,并獲得數據庫當時的一致快照。因此,該技術支持時間點恢復:可以在進行基本備份后的任何時間點將數據庫恢復到其狀態。
- 如果我們不斷地將一系列 WAL 文件提供給另一臺已經加載了相同基本備份文件的機器,我們就有了一個熱備用系統:在任何時候我們都可以啟動第二臺機器,它會是一個幾乎最新的副本數據庫。
pg_dump和pg_dumpall不生成文件系統級備份,并且不能用作連續歸檔解決方案的一部分。這樣的轉儲是合乎邏輯的,包含的信息不足以供WAL replay使用。
與普通文件系統備份技術一樣,這種方法只能支持整個數據庫集群的恢復,而不能支持子集的恢復。此外,它還需要大量的存檔存儲:基本備份可能非常龐大,繁忙的系統將產生大量必須存檔的WAL流量。盡管如此,在許多需要高可靠性的情況下,它仍然是首選的備份技術。
要使用連續存檔(許多數據庫供應商也稱為“在線備份”)成功恢復,您需要一系列連續的存檔WAL文件,這些文件至少可以追溯到備份的開始時間。因此,在開始第一次備份之前,您應該設置并測試歸檔WAL文件的過程。因此,我們首先討論歸檔WAL文件的機制。
設置 WAL 歸檔
從抽象意義上講,運行的PostgreSQL系統會產生無限長的WAL記錄序列。系統將該序列物理地劃分為WAL段文件,每個文件通常為16MB(盡管段大小可以在initdb期間更改)。段文件的數字名稱反映了它們在抽象序列中的位置。當不使用WAL歸檔時,系統通常只創建幾個段文件,然后通過將不再需要的段文件重命名為更高的段號來“回收”它們。假設內容位于最后一個檢查點之前的段文件不再受關注,可以循環使用。
在歸檔WAL數據時,我們需要在每個段文件被填充后捕獲其內容,并在段文件被循環使用之前將該數據保存在某個位置。根據應用程序和可用硬件的不同,可能有許多不同的“將數據保存到某處”的方法:我們可以將段文件復制到另一臺機器上的NFS掛載目錄,將其寫入磁帶機(確保有一種方法來識別每個文件的原始名稱),或者將它們批處理在一起并將它們刻錄到 CD 上,或者其他備份保存方式。為了給數據庫管理員提供靈活性,PostgreSQL盡量不對歸檔方式進行任何限制。相反,PostgreSQL允許管理員指定要執行的shell命令,以將完成的段文件復制到需要的任何地方。這個命令可以像cp一樣簡單,也可以調用復雜的shell腳本——這完全取決于你的心情。
要啟用WAL存檔,請將WAL_級別配置參數設置為“副本”或更高級別,將“存檔”模式設置為“打開”,并指定要在“存檔”命令配置參數中使用的shell命令。實際上,這些設置將始終放在postgresql中。conf文件。在archive_命令中,%p將替換為要存檔的文件的路徑名,而%f僅替換為文件名。(路徑名相對于當前工作目錄,即集群的數據目錄。)如果需要在命令中嵌入實際的%字符,請使用%%。最簡單有用的命令如下:
要啟用 WAL 歸檔,請將wal_level配置參數設置為replica或higher,將archive_mode設置為on,并在archive_command配置參數中指定要使用的 shell 命令。實際上,這些設置將始終放在postgresql.conf文件中,在archive_command配置文件中,%p替換為要歸檔的文件的路徑名,而%f僅替換為文件名。(路徑名相對于當前工作目錄,即集群的數據目錄。)如果需要在命令中嵌入%字符,請使用%%。最簡單有用的命令是這樣的:
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows
將可歸檔的WA段復制到目錄/mnt/server/archivedir。(這只是一個例子,不是一個建議,可能不適用于所有平臺。)替換%p和%f參數后,實際執行的命令可能如下所示:
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
將為每個要歸檔的新文件生成一個類似的命令。
存檔命令將在運行PostgreSQL server的同一用戶的所有權下執行。由于正在歸檔的一系列WAL文件實際上包含了數據庫中的所有內容,因此您需要確保歸檔的數據不會被窺探;例如,歸檔到一個沒有所屬組或全局讀取權限的目錄中。
當且僅當存檔命令成功時,它才返回零退出狀態,這一點很重要。得到零結果后,PostgreSQL將假定該文件已成功存檔,并將刪除或回收該文件。然而,非零狀態告訴PostgreSQL該文件沒有被歸檔;它將定期重試,直到成功。
當歸檔命令被一個信號(不是用作數據庫關閉的一部分的SIGTERM )或退出狀態大于 125 的 shell 錯誤(例如未找到命令)終止時,歸檔進程將中止,并由postmaster重新啟動。在這種情況下,失敗不會在pg_stat_archiver中報告。
“歸檔”命令通常應設計為拒絕覆蓋任何預先存在的存檔文件。這是一項重要的安全功能,可以在管理員出錯(例如將兩臺不同數據庫的輸出發送到同一個存檔目錄)時保護存檔的完整性。
建議測試您編輯的歸檔命令,以確保它確實不會覆蓋現有文件,并且在這種情況下返回非零狀態。上面針對Unix的示例命令通過包含單獨的測試步驟來確保這一點。在某些Unix平臺上,cp具有諸如-i之類的開關,可用于不太詳細地執行相同的操作,但是不應該在未驗證返回正確的退出狀態的情況下依賴這些開關。(尤其是,當使用-i并且目標文件已經存在時,cp將返回狀態零,這不是期望的行為。)
在設計歸檔設置時,考慮如果存檔命令重復失敗會發生什么,因為某些方面需要管理員干預或歸檔空間不足。例如,如果在沒有自動轉換器的情況下寫入磁帶,就可能會發生這種情況;當磁帶填滿時,在交換磁帶之前,不能再存檔任何內容。您應確保向管理員報告錯誤情況或請求,以便能夠合理快速地解決問題。pg_wal/目錄將繼續填充wal段文件,直到情況得到解決。(如果包含pg_wal/的文件系統已滿,PostgreSQL將緊急關閉。提交的事務不會丟失,但數據庫將保持脫機狀態,直到釋放一些空間。)
歸檔命令的速度并不重要,只要它能夠跟上數據庫生成 WAL 數據的平均速率即可。即使歸檔過程稍有滯后,正常操作仍將繼續。如果歸檔嚴重滯后,這將增加災難發生時丟失的數據量。這還意味著pg_wal/目錄將包含大量尚未歸檔的段文件,這些文件最終可能會超出可用磁盤空間。建議您監控存檔過程,以確保其按預期工作。
在編寫歸檔命令時,您應該假設要歸檔的文件名最長為 64 個字符,并且可以包含 ASCII 字母、數字和點的任意組合。不必保留原始相對路徑 ( %p),但必須保留文件名 ( %f)。
請注意,雖然WAL歸檔將允許您恢復對PostgreSQL數據庫中的數據所做的任何修改,但它不會恢復對配置文件(即PostgreSQL.conf、pg_hba.conf和pg_ident.conf)所做的更改,因為這些文件是手動編輯的,而不是通過SQL操作。您可能希望將配置文件保存在將由常規文件系統備份過程備份的位置。
archive命令僅在已完成的WAL段上調用。因此,如果您的數據庫只生成很少的WAL數據量(或者在產生WAL數據量時有空閑時間),那么從事務完成到在歸檔存儲中安全記錄之間可能會有很長的延遲。要限制未歸檔數據的保存時間,可以設置archive_timeout,以強制數據庫至少頻繁地切換到新的WAL段文件。請注意,由于強制切換而提前歸檔的歸檔文件的長度仍然與完全完整的文件相同。因此,設置一個很短的archive_timeout是不明智的——它會使存檔存儲空間膨脹。一分鐘左右的archive_timeout設置通常是合理的。
此外,如果您想確保盡快歸檔剛剛完成的事務,可以使用pg_switch_wal手動強制進行段切換。
當wal_level設置我minimal時,會優化一些SQL命令以避免wal日志記錄。如果在執行其中一條語句時打開了存檔或流式復制,WAL將無法包含足夠的信息來進行存檔恢復。(崩潰恢復不受影響。)因此,wal_level只能在數據庫啟動時更改。但是,可以通過重新加載配置文件來更改archive_command。如果希望暫時停止存檔,一種方法是將archive_command設置為空字符串 (’’)。這將導致WAL文件在pg_wal/中累積,直到archive_command重新建立起工作。
進行基本備份
執行基本備份的最簡單方法是使用pg_basebackup工具。它可以將基本備份創建為常規文件或 tar 存檔。如果需要比pg_basebackup提供的更大的靈活性,您還可以使用低級 API 進行基本備份。
不必擔心進行基本備份所需的時間。但是,如果您通常在full_page_writes禁用的情況下運行數據庫,您可能會注意到在備份運行時性能下降,因為full_page_writes在備份模式下實際上是強制打開的。
要使用備份,您需要保留在文件系統備份期間和之后生成的所有 WAL 段文件。為了幫助做到這一點,基本備份過程會創建一個備份歷史文件,該文件會立即存儲到 WAL 存檔區域中。該文件以文件系統備份所需的第一個 WAL 段文件命名。例如,如果起始 WAL 文件是0000000100001234000055CD備份歷史文件,則將命名為0000000100001234000055CD.007C9330.backup. (文件名的第二部分代表 WAL 文件中的確切位置,通常可以忽略。)一旦您安全地歸檔了文件系統備份和備份期間使用的 WAL 段文件(如備份歷史文件中所指定),則不再需要名稱數字較小的所有存檔 WAL 段來恢復文件系統備份,并且可以將其刪除。但是,您應該考慮保留多個備份集,以絕對確定您可以恢復數據。
備份歷史文件只是一個小文本文件。它包含您給pg_basebackup的標簽字符串,以及備份的開始和結束時間和WAL段。如果使用標簽標識關聯的轉儲文件,則存檔的歷史文件足以告訴您要恢復哪個轉儲文件。
由于您必須將所有存檔的WAL文件保留到上一次基本備份,因此基本備份之間的間隔通常應根據您希望在存檔的WAL文件上花費的存儲量來選擇。你也應該考慮你準備花多長時間來恢復,如果需要恢復的話,系統將不得不重放所有的WAL段,這可能需要一段時間,如果它已經很長一段時間以來的最后一個基礎備份。
備份歷史文件只是一個小文本文件。它包含您提供給pg_basebackup的標簽字符串,以及備份的開始和結束時間和 WAL 段。如果使用標簽來識別關聯的轉儲文件,那么歸檔的歷史文件就足以告訴您要恢復哪個轉儲文件。
由于您必須將所有已歸檔的 WAL 文件保留到您上次的基本備份,因此基本備份之間的間隔通常應根據您希望在已歸檔的 WAL 文件上花費多少存儲空間來選擇。您還應該考慮準備花多長時間進行恢復,如果需要恢復,那么系統將不得不重放所有的 WAL 段,如果自上次基本備份以來已經很長時間,那么恢復將相應的花費很長的時間。
使用低級 API 進行基本備份
使用低級API進行基本備份的過程比pg_basebackup方法包含更多步驟,但相對簡單。按順序執行這些步驟非常重要,并且在繼續下一步之前驗證步驟是否成功。
低級基本備份可以以非獨占或獨占的方式進行。建議使用非獨占方法,獨占方法不推薦使用,最終將被刪除。
進行非獨占低級備份
非獨占低級別備份是指允許運行其他并發備份的備份(使用相同備份API啟動的備份和使用pg_basebackup啟動的備份)。
- 確保 WAL 存檔已啟用并正常工作。
- 以有權運行 pg_start_backup 的用戶(超級用戶或已被授予 EXECUTE 該功能的用戶)連接到數據庫(哪個數據庫無關緊要),并發出以下命令:
SELECT pg_start_backup('label', false, false);
其中label是用于唯一標識此備份操作的任何字符串。調用pg_start_backup的連接必須保持到備份結束,否則備份將自動中止。
默認情況下,pg_start_backup可能需要很長時間才能完成。這是因為它執行一個檢查點,并且檢查點所需的I/O將分散在很長一段時間內,默認情況下是檢查點間隔的一半(請參閱配置參數checkpoint_completion_target)。這通常是您想要的,因為它將對查詢處理的影響降至最低。如果希望盡快啟動備份,請將第二個參數更改為true,這將使用盡可能多的I/O立即發出檢查點。
第三個參數為false時,pg_start_backup將啟動非獨占的基本備份。
-
使用任何方便的文件系統備份工具(如tar或cpio,而不是pg_dump或pg_dumpall)執行備份。在執行此操作時,既沒有必要也不希望停止數據庫的正常操作。
-
在與以前相同的連接中,發出以下命令:
SELECT * FROM pg_stop_backup(false, true);
這將終止備份模式。在主節點上,它還會自動切換到下一個 WAL 段。在備節點上,無法自動切換 WAL 段,因此您可能希望pg_switch_wal在主數據庫上運行以執行手動切換。切換的原因是為了安排在備份間隔期間寫入的最后一個 WAL 段文件準備歸檔。
pg_stop_backup將返回一行三個值。第二個字段應寫入備份根目錄中名為backup_label的文件。第三個字段應寫入名為tablespace_map的文件,除非該字段為空。這些文件對備份工作至關重要,必須逐字節寫入,無需修改,這可能需要以二進制模式打開文件。
- 備份過程中活動的WAL段文件歸檔后,即可完成備份。
pg_stop_backup的第一個返回值標識的文件是形成完整備份文件集所需的最后一段。在主節點上,如果archive_mode啟用且wait_for_archive參數為true,pg_stop_backup則在最后一個段被歸檔之前不會返回。在備節點上,archive_mode必須always為pg_stop_backup等待。由于您已經配置了archive_command,這些文件的存檔會自動進行歸檔。 在大多數情況下,這會很快發生,但建議您監控存檔系統以確保沒有延遲。如果歸檔進程由于歸檔命令失敗而落后,它將繼續重試,直到歸檔成功并且備份完成。如果您希望對pg_stop_backup的執行設置時間限制,請設置適當的statement_timeout值,但請注意,如果pg_stop_backup因此終止,您的備份可能無效。
如果備份過程監控并確保備份所需的所有 WAL 段文件都已成功存檔,則可以將wait_for_archive參數(默認為true)設置為false,以便pg_stop_backup在停止備份記錄寫入WAL后立即返回。默認情況下,pg_stop_backup將等待所有 WAL 歸檔,這可能需要一些時間。必須謹慎使用此選項:如果未正確監控 WAL 歸檔,則備份可能不包括所有 WAL 文件,因此將不完整且無法恢復。
進行獨占低級備份
獨占備份方法已被棄用,應避免使用。在PostgreSQL 9.6之前,這是唯一可用的低級方法,但現在建議所有用戶升級腳本以使用非獨占備份。
獨占備份的過程與非獨占備份的過程基本相同,但在幾個關鍵步驟上有所不同。這種類型的備份只能在主數據庫上進行,不允許并發備份。此外,由于它會創建一個備份標簽文件(如下所述),因此會在崩潰后阻止主數據庫的自動重啟。另一方面,從備份或備用文件中錯誤刪除此文件是常見的錯誤,這可能會導致嚴重的數據損壞。如果需要使用這種方法,可以使用以下步驟。
獨占備份的過程與非獨占備份的過程基本相同,但在幾個關鍵步驟上有所不同。這種類型的備份只能在主節點上進行,并且不允許并發備份。此外,因為它創建了一個備份標簽文件(如下所述),所以它可以阻止主節點在崩潰后自動重啟。另一方面,從備份或standby中錯誤地刪除此文件是一個常見錯誤,這可能導致嚴重的數據損壞。如果需要使用該方法,可以使用以下步驟。
-
確保 WAL 歸檔已啟用并正常工作。
-
以有權運行 pg_start_backup 的用戶(超級用戶或已被授予 EXECUTE 功能的用戶)連接到數據庫(哪個數據庫無關緊要)并發出命令:
SELECT pg_start_backup('label');其中
label是要用于唯一標識此備份操作的任何字符串。pg_start_backup在集群目錄中創建一個名為 的備份標簽文件,backup_label其中包含有關您的備份的信息,包括開始時間和標簽字符串。該函數還在集群目錄中創建一個名為tablespace_map的表空間映射文件,其中包含有關表空間符號鏈接的信息(pg_tblspc/如果存在一個或多個此類鏈接)。如果您需要從中恢復,這兩個文件對于備份的完整性都至關重要。默認情況下,
pg_start_backup可能需要很長時間才能完成。這是因為它執行一個檢查點,檢查點所需的I/O將在相當長的一段時間內分散,默認情況下是檢查點間隔的一半(請參閱配置參數checkpoint_completion_target)。這通常是您想要的,因為它將對查詢處理的影響降至最低。如果要盡快啟動備份,請使用:默認情況下,
pg_start_backup可能需要很長時間才能完成。這是因為它執行一個檢查點,并且檢查點所需的 I/O 將分散在很長一段時間內,默認情況下是檢查點間間隔的一半(請參閱配置參數checkpoint_completion_target)。這通常是您想要的,因為它最大限度地減少了對查詢處理的影響。如果您想盡快開始備份,請使用:SELECT pg_start_backup('label', true);這將會使檢查點盡快完成。
-
使用任何方便的文件系統備份工具(如tar或cpio,而不是pg_dump或pg_dumpall)執行備份。在執行此操作時,既沒有必要也不希望停止數據庫的正常操作。
如上所述,如果數據庫在備份期間崩潰,則在
backup_label手動從PGDATA目錄中刪除文件之前,可能無法重新啟動。請注意,在恢復備份時切勿刪除backup_label文件,因為這會導致數據損壞。混淆何時刪除此文件是導致數據損壞的常見原因;務必確保僅在現有主設備上刪除文件,而不是在構建備用數據庫或恢復備份時刪除該文件,即使您正在構建一個隨后將被提升為新主數據庫的備用數據庫。 -
再次以有權運行 pg_stop_backup 的用戶(超級用戶,或已被授予 EXECUTE 功能的用戶)連接到數據庫,并發出命令:
SELECT pg_stop_backup();此函數終止備份模式,并自動切換到下一個WAL段。切換的原因是為了在備份間隔期間寫入的最后一個WAL段準備歸檔。
使用獨占備份模式時,絕對必須確保pg_stop_備份在備份結束時成功完成。即使備份本身失敗,例如由于磁盤空間不足,如果未能調用pg_stop_backup,數據庫也會無限期地處于備份模式,導致未來的備份失敗,并增加備份標簽存在期間重啟失敗的風險。
-
備份過程中活動的WAL段文件歸檔后,即可完成備份。
pg_stop_backup的結果所標識的文件是形成一套完整的備份文件集所需的最后一個段。如果archive_mode啟用,pg_stop_backup則在最后一個段被歸檔之前不會返回。由于配置了archive_command,這些文件將自動進行存檔。在大多數情況下,這種情況發生得很快,但建議您監控存檔系統以確保沒有延遲。如果歸檔進程由于歸檔命令失敗而落后,它將繼續重試,直到歸檔成功并且備份完成。使用獨占備份模式時,確保
pg_stop_backup在備份結束時成功完成是絕對必要的。即使備份本身失敗(例如由于磁盤空間不足),pg_stop_backup調用失敗也會使數據庫無限期地處于備份模式,從而導致未來的備份失敗,并增加在backup_label存在的時間內重新啟動失敗的風險。
備份數據目錄
如果在使用某些文件系統備份工具進行復制過程中,復制的文件發生了更改,則會發出警告或錯誤。在對活動數據庫進行基本備份時,這種情況是正常的,而不是錯誤。但是,您需要確保能夠區分此類complaints和真正的錯誤。例如,某些版本的rsync會為“消失的源文件”返回一個單獨的退出代碼,您可以編寫一個驅動程序腳,將此退出代碼作為非錯誤情況接受。此外,如果在 tar復制文件時文件被截斷,那么某些GNU版本的 tar返回的錯誤代碼與致命錯誤無法區分。幸運的是,1.16及更高的GNU版本 tar在備份過程中如果文件發生更改,將以1退出,其他錯誤將以2退出。使用1.23 及更高的GNU版本的 tar ,您可以使用警告選項--warning=no-file-changed --warning=no-file-removed來隱藏相關的警告消息。
確保您的備份包括數據庫集群目錄下的所有文件(例如,/usr/local/pgsql/data)。如果您正在使用不在此目錄下的表空間,請注意將它們也包括在內(并確保您的備份將符號鏈接存檔為鏈接,否則恢復將損壞您的表空間)。
但是,您應該從備份中省略集群的pg_wal/子目錄中的文件。這種輕微的調整是值得的,因為它降低了恢復時出錯的風險。如果pg_wal/是指向集群目錄之外某個位置的符號鏈接,這很容易理解,因為出于性能原因,這是一種常見的設置。您可能還想排除postmaster.pid和postmaster.opts,它記錄有關正在運行的postmaster的信息,而不是關于最終將使用此備份的postmaster的信息。(這些文件可能會混淆pg_ctl。)
從備份中省略集群的pg_replslot/目錄中的文件通常是一個好主意,這樣主數據庫上的復制槽就不會成為備份的一部分。否則,后續使用備份創建standby可能會導致standby上無限期保留 WAL 文件,如果啟用hot standby,則可能會導致主數據庫上的WAL文件膨脹,因為使用這些復制槽的客戶端仍將連接并更新主節點上的插槽,而不是standby節點上的插槽。即使備份僅用于創建新主節點,復制復制槽也不會特別有用,因為在新的主節點上線時,這些插槽的內容可能已經嚴重過時。
目錄pg_dynshmem/、pg_notify/、pg_serial/、pg_snapshots/、pg_stat_tmp/和pg_subtrans/(但不是目錄本身)的內容可以從備份中省略,因為它們將在 postmaster 啟動時初始化。如果設置了stats_temp_directory,并且位于數據目錄下,則該目錄的內容也可以省略。
任何以pgsql_tmp開頭的文件或目錄都可以從備份中省略。這些文件在postmaster 啟動時被刪除,并且將根據需要重新創建目錄。
pg_internal.init只要找到該名稱的文件,就可以從備份中省略文件。這些文件包含在恢復時始終重建的關系緩存數據。
備份標簽文件包括您提供給pg_start_backup的標簽字符串、pg_start_backup的運行時間以及起始 WAL 文件的名稱。因此,在出現混淆的情況下,可以查看備份文件內部并準確確定轉儲文件來自哪個備份會話。表空間映射文件包括存在于pg_tblspc/目錄中的符號鏈接名稱以及每個符號鏈接的完整路徑。這些文件不僅僅是供你參考的;它們的存在和內容對于系統恢復過程的正常運行至關重要。
也可以在數據庫停止時進行備份。在這種情況下,顯然不能使用pg_start_backup或 pg_stop_backup,因此您將被留在自己的設備上,以跟蹤哪個備份是哪個備份以及相關WAL文件的備份時間。通常最好遵循上面的連續歸檔過程。
使用連續存檔備份進行恢復
在最壞的情況已經發生后,你需要從備份中恢復。以下是恢復程序:
- 如果數據庫正在運行,請停止數據庫。
- 如果有空余的空間,請將整個集群數據目錄和任何表空間復制到一個臨時位置,以備不時之需。注意,此預防措施將要求您的系統上有足夠的可用空間來保存現有數據庫的兩個副本。如果您沒有足夠的空間,您至少應該保存集群
pg_wal子目錄的內容,因為它可能包含在系統關閉之前未歸檔的日志。 - 刪除集群數據目錄下以及正在使用的任何表空間的根目錄下的所有現有文件和子目錄。
- 從文件系統備份中還原數據庫文件。確保以正確的所有權(數據庫系統用戶,而不是
root!)和正確的權限進行還原。如果正在使用表空間,則應驗證pg_tblspc/中的符號鏈接是否已正確還原。 - 刪除
pg_wal/中存在的所有文件;這些來自文件系統備份,因此可能已過時,而不是最新版本。如果您根本沒有存檔pg_wal/文件,那么就使用適當的權限重新創建它,如果您之前用符號鏈接方式設置過,就需要確保將其重新建立為符號鏈接。 - 如果您在步驟 2 中保存了未歸檔的 WAL 段文件,請將它們復制到
pg_wal/。(最好是復制它們,而不是移動它們,這樣如果出現問題,你仍然有未修改的文件。) - 在
postgresql.conf中設置恢復配置設置,并recovery.signal在集群數據目錄中創建一個文件。您可能還需要臨時修改pg_hba.conf以防止普通用戶連接,直到您確定恢復成功。 - 啟動數據庫。數據庫將進入恢復模式,并繼續讀取它需要的存檔 WAL 文件。如果由于外部錯誤而終止恢復,則只需重新啟動數據庫,即可繼續恢復。恢復過程完成后,數據庫將刪除
recovery.signal(以防止以后意外地重新進入恢復模式),然后開始正常的數據庫操作。 - 檢查數據庫的內容以確保您已恢復到所需的狀態。如果沒有,請返回步驟 1。如果一切正常,請通過恢復
pg_hba.conf正常讓用戶連接。
所有這一切的關鍵部分是設置一個恢復配置,該配置描述了您希望恢復的方式以及恢復應該運行的距離。必須指定的是restore_command,它告訴PostgreSQL如何檢索歸檔的 WAL 文件段。和archive_command一樣,這是一個 shell 命令字符串。它可以包含%f, 替換為所需日志文件的名稱,以及%p, 替換為要將日志文件復制到的路徑名。(路徑名相對于當前工作目錄,即集群的數據目錄。)如果需要在命令中嵌入實際的%字符,請寫入%%。最簡單有用的命令如下:
restore_command = 'cp /mnt/server/archivedir/%f %p'
它將從/mnt/server/archivedir目錄中復制以前存檔的 WAL 段。當然,您想使用更復雜的東西,甚至可以使用一個shell腳本來請求裝入適當的磁帶。
重要的是,該命令在失敗時返回非零退出狀態。該命令將被稱為請求歸檔中不存在的文件;當被詢問時,它必須返回非零。這不是錯誤情況。例外情況是,如果命令被一個信號(SIGTERM除外,它用作數據庫關閉的一部分)或 shell 的一個錯誤(例如找不到命令)終止的,則恢復將中止,數據庫將不會啟動。
并非所有請求的文件都是 WAL 段文件;您還應該期望對帶有 . 后綴的文件的請求.history。另請注意,%p路徑的基本名稱將不同于%f; 不要指望它們可以互換。
并非所有請求的文件都是 WAL 段文件;您還可以對帶有 . 后綴的文件的請求,比如.history。另請注意,%p路徑的基本名稱將不同于%f; 不要指望它們可以互換。
在歸檔中找不到的 WAL 段將在pg_wal/; 這允許使用最近未歸檔的段。但是,歸檔中可用的段將優先于pg_wal/.
通常情況下,恢復將通過所有可用的 WAL 段進行,從而將數據庫恢復到當前時間點(或盡可能接近可用的 WAL 段)。因此,正常恢復將以“未找到文件”消息結束,錯誤消息的確切文本取決于您設置的restore_command. 您可能還會在恢復開始時看到名為00000001.history的文件。 這也是正常的,在簡單的恢復情況下并不表示有問題;
如果您想恢復到以前的某個時間點(例如,就在初級DBA刪除主事務表之前),只需指定所需的停止點。您可以通過日期/時間、還原點名稱或特定事務ID的完成來指定停止點,稱為“恢復目標”。其實只有日期/時間和命名還原點選項非常有用,因為沒有工具可以幫助您準確地識別要使用的事務ID。
停止點必須在基礎備份的結束時間之后,即
pg_stop_backup的結束時間。您不能使用基本備份來恢復到該備份正在進行的時間。(要恢復到這樣的時間,您必須回到以前的基本備份并從那里前滾。)
如果恢復發現損壞的WAL數據,恢復將在該點停止,服務器將不會啟動。在這種情況下,恢復過程可以從頭開始重新運行,在損壞點之前指定“恢復目標”,以便恢復可以正常完成。如果由于外部原因(如系統崩潰或WAL存檔無法訪問)而導致恢復失敗,則可以簡單地重新啟動恢復,恢復將幾乎從失敗的地方重新啟動。恢復重啟的工作原理與正常操作中的檢查點非常相似:服務器定期將其所有狀態強制放到磁盤上,然后更新pg_控制文件,以指示不需要再次掃描已處理的WAL數據。
如果恢復發現損壞的 WAL 數據,恢復將在該點停止,并且數據庫將不會啟動。在這種情況下,恢復過程可以從頭開始重新運行,在損壞點之前指定一個“恢復目標”,以便恢復可以正常完成。如果由于外部原因恢復失敗(如系統崩潰或WAL存檔無法訪問),則可以簡單地重新啟動恢復,并且它將幾乎從失敗的地方重新啟動。恢復重啟的工作方式很像正常操作中的檢查點:數據庫定期其所有狀態強制放到磁盤上,然后更新pg_control文件,以指示不需要再次掃描已經處理的 WAL 數據。
時間線
將數據庫恢復到以前的時間點的能力會產生一些類似于關于時間旅行和平行宇宙的科幻故事的復雜性。例如,在數據庫的原始歷史記錄中,假設您在周二晚上 5:15 PM 刪除了一個關鍵表,但直到周三中午才意識到自己的錯誤。毫不擔心,您取出備份,恢復到周二晚上 5:14 PM 的時間點,然后開始運行。在這個數據庫宇宙的歷史,你從來沒有刪除過表。但是假設您后來意識到這不是一個好主意,并想回到原始歷史中的某個星期三早上。如果在您的數據庫啟動并運行時,它會覆蓋一些 WAL 段文件,這些文件會影響您現在希望可以返回的時間,那么您將無法做到這一點。因此,為避免這種情況,您需要將在執行時間點恢復后生成的一系列 WAL 記錄與在原始數據庫歷史記錄中生成的記錄區分開來。
為了解決這個問題,PostgreSQL有一個時間線的概念. 每當歸檔恢復完成時,都會創建一個新的時間線來識別在該恢復之后生成的一系列 WAL 記錄。時間線 ID 號是 WAL 段文件名的一部分,因此新時間線不會覆蓋先前時間線生成的 WAL 數據。事實上,可以歸檔許多不同的時間線。雖然這似乎是一個無用的功能,但它通常是救命稻草。考慮一下您不太確定要恢復到哪個時間點的情況,因此必須通過反復試驗進行多次時間點恢復,直到找到從舊歷史分支的最佳位置。如果沒有時間表,這個過程很快就會產生無法控制的混亂局面。使用時間線,您可以恢復到任何先前的狀態,包括您之前放棄的時間線分支中的狀態。
每次創建新的時間線時,PostgreSQL都會創建一個“時間線歷史”文件,顯示它從哪個時間線分支以及何時分支。當從包含多個時間線的存檔中恢復時,這些歷史文件是允許系統選擇正確的 WAL 段文件所必需的。因此,它們就像 WAL 段文件一樣被歸檔到 WAL 歸檔區。歷史文件只是小文本文件,因此將它們無限期地保存起來既便宜又合適(與大的段文件不同)。如果愿意,您可以在歷史文件中添加評論,以記錄您自己關于如何以及為何創建此特定時間線的注釋。當您通過實驗獲得大量不同的時間線時,此類評論將特別有價值。
恢復的默認行為是沿進行基本備份時的當前時間線進行恢復。如果您希望恢復到某個子時間線(即,您希望返回到恢復嘗試后自身生成的某個狀態),您需要在recovery.conf中指定目標時間線 ID 。您無法恢復到早于基本備份分支的時間線。
提示和示例
此處提供了一些配置連續歸檔的技巧。
獨立熱備份
如果需要更靈活地復制備份文件,也可以將較低級別的過程用于獨立熱備份。要準備低級別的獨立熱備份,請確保wal_level設置為“副本”或更高級別,archive_mode設置為“打開”,并設置一個archive_命令,。例如:
可以使用PostgreSQL的備份工具來生成獨立的熱備份。這些備份不能用于時間點恢復,但備份和恢復速度通常比pg_dump快得多。(它們也比pg_dump轉儲大得多,因此在某些情況下速度優勢可能會被抵消。)
與基本備份一樣,生成獨立熱備份的最簡單方法是使用pg_basebackup工具。如果調用時包含-X參數,則使用備份所需的所有預寫日志將自動包含在備份中,無需特殊操作即可恢復備份。
如果需要更靈活地復制備份文件,也可以將較低級別的進程用于獨立熱備份。要準備低級別的獨立熱備份,請確保wal_level設置為replica或更高,設置archive_mode為on,并設置archive_command,該命令僅在存在切換文件時執行歸檔。例如:
archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
當/var/lib/pgsql/backup_in_progress存在時,此命令將執行歸檔,否則將以靜默方式返回零退出狀態(允許PostgreSQL回收不需要的 WAL 文件)。
通過這種準備,可以使用如下腳本進行備份:
touch /var/lib/pgsql/backup_in_progress
psql -c "select pg_start_backup('hot_backup');"
tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
psql -c "select pg_stop_backup();"
rm /var/lib/pgsql/backup_in_progress
tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
首先創建switch 文件/var/lib/pgsql/backup_in_progress,以便歸檔已完成的WAL文件。備份后,將刪除switch文件。然后將歸檔的 WAL 文件添加到備份中,以便基本備份和所有必需的 WAL 文件都屬于同一個tar文件。請記住在備份腳本中添加錯誤處理。
壓縮存檔日志
如果需要考慮歸檔存儲大小,可以使用gzip壓縮歸檔文件:
archive_command = 'gzip < %p > /mnt/server/archivedir/%f.gz'
然后,您將需要在恢復期間使用gunzip :
restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %p'
Archive_command腳本
很多人選擇使用腳本來定義他們的archive_command,以便postgresql.conf 條目看起來非常簡單:
archive_command = 'local_backup_script.sh "%p" "%f"'
每當您想在歸檔過程中使用多個命令時,建議使用單獨的腳本文件。這允許在腳本中管理所有復雜性,腳本可以用流行的腳本語言編寫,例如bash或perl。
可能在腳本中解決的需求示例包括:
- 復制數據以保護異地數據存儲
- 批處理 WAL 文件,以便每三個小時傳輸一次,而不是一次傳輸一個
- 與其他備份和恢復軟件的接口
- 與監控軟件接口以報告錯誤
提示
使用archive_command腳本時,最好啟用logging_collector。然后,從腳本寫入stderr的任何消息都將出現在數據庫服務器日志中,如果復雜配置失敗,則可以輕松診斷它們。
注意事項
在本文中,連續歸檔技術存在一些限制。這些可能會在未來的版本中修復:
- 如果在進行基本備份時執行
CREATE DATABASE命令,然后在基本備份仍在進行時修改了CREATE DATABASE復制的模板數據庫,則恢復可能會導致這些修改也傳播到創建的數據庫中. 這當然是不可取的。為避免這種風險,最好不要在進行基本備份時修改任何模板數據庫。 CREATE TABLESPACE命令使用文字絕對路徑進行 WAL 記錄,因此將作為具有相同絕對路徑的表空間創建重放。如果在另一臺機器上重放日志,這可能是不可取的。即使日志在同一臺機器上重放,但將其放在新的數據目錄中,也可能很危險:重放仍然會覆蓋原始表空間的內容。為避免此類潛在問題,最佳實踐是在創建或刪除表空間后進行新的基本備份。
還應該注意的是,默認的WAL格式相當龐大,因為它包含許多磁盤頁面快照。這些頁面快照旨在支持崩潰恢復,因為我們可能需要修復部分寫入的磁盤頁面。根據您的系統硬件和軟件,部分寫入的風險可能小到可以忽略,在這種情況下,您可以通過使用full_page_writes參數關閉頁面快照來顯著減少歸檔日志的總量。關閉頁面快照不會阻止將日志用于 PITR 操作。未來發展的一個領域是通過刪除不必要的頁面副本來壓縮存檔的 WAL 數據,即使在full_page_writes開啟。同時,管理員可能希望通過盡可能增加檢查點間隔參數來減少 WAL 中包含的頁面快照的數量。
翻譯自:[26.3. Continuous Archiving and Point-in-Time Recovery (PITR)](https://www.postgresql.org/docs/14/continuous-archiving.html)




