PostgreSQL 始終在其叢集資料目錄的 pg_wal/
子目錄下維護一個預寫日誌 (WAL)。該日誌記錄了資料庫資料檔案中的所有更改。該日誌主要用於崩潰安全目的:如果系統崩潰,可以透過“重放”自上次檢查點以來的日誌條目來將資料庫恢復到一致狀態。然而,該日誌的存在使得可以採用第三種策略來備份資料庫:我們可以將檔案系統級別的備份與 WAL 檔案備份結合起來。如果需要恢復,我們恢復檔案系統備份,然後從備份的 WAL 檔案重放,將系統帶到當前狀態。此方法比前兩種方法更復雜,但具有一些顯著的優點。
我們不需要一個完美的、一致的檔案系統備份作為起點。備份中的任何內部不一致都將透過日誌重放得到糾正(這與崩潰恢復期間發生的情況沒有太大區別)。因此,我們不需要檔案系統快照功能,只需要tar 或類似的歸檔工具。
由於我們可以將無限長的 WAL 檔案序列用於重放,因此透過繼續歸檔 WAL 檔案即可實現連續備份。這對於大型資料庫尤其有價值,因為頻繁進行完整備份可能不方便。
不必將 WAL 條目重放到末尾。我們可以在任何時候停止重放,並得到資料庫在該時刻的精確一致快照。因此,此技術支援時間點恢復:可以將其恢復到自基礎備份建立以來資料庫的任何時間點狀態。
如果我們持續將 WAL 檔案系列傳輸到已載入相同基礎備份檔案的另一臺機器上,我們就擁有一個熱備用系統:在任何時候,我們都可以啟動第二臺機器,它將擁有一個近乎當前的資料庫副本。
pg_dump 和 pg_dumpall 不生成檔案系統級別的備份,也不能用作連續歸檔解決方案的一部分。此類轉儲是邏輯的,不包含足夠的資訊供 WAL 重放使用。
與純檔案系統備份技術一樣,此方法只能支援恢復整個資料庫叢集,而不能恢復子集。此外,它需要大量的歸檔儲存:基礎備份可能很龐大,繁忙的系統會生成大量必須歸檔的 WAL 流量。儘管如此,在需要高可靠性的許多情況下,它仍然是首選的備份技術。
要成功使用連續歸檔(許多資料庫供應商也稱之為“線上備份”)進行恢復,您需要一個連續的歸檔 WAL 檔案序列,該序列至少回溯到備份的開始時間。因此,要開始,您應該在執行第一個基礎備份之前設定並測試您的 WAL 檔案歸檔過程。因此,我們首先討論 WAL 檔案歸檔的機制。
從抽象意義上講,正在執行的PostgreSQL 系統會生成一個無限長的 WAL 記錄序列。該系統將此序列物理上劃分為 WAL段檔案,這些檔案通常為 16MB(儘管段大小可以在initdb 時更改)。段檔案被賦予數字名稱,反映它們在抽象 WAL 序列中的位置。當不使用 WAL 歸檔時,系統通常只建立幾個段檔案,然後透過重新命名不再需要的段檔案為更高的段號來“回收”它們。假定內容早於最後一個檢查點的段檔案不再有趣,可以回收。
在歸檔 WAL 資料時,我們需要在每個段檔案被回收使用之前捕獲其內容並將其儲存到某處。根據應用程式和可用硬體,“將資料儲存到某處”可能有很多不同的方法:我們可以將段檔案複製到另一臺機器上的 NFS 掛載目錄,將它們寫入磁帶驅動器(確保您有辦法識別每個檔案的原始名稱),或者將它們批次打包刻錄到 CD 上,或者其他任何方法。為了給資料庫管理員提供靈活性,PostgreSQL 儘量不假設歸檔將如何完成。相反,PostgreSQL 允許管理員指定一個 shell 命令或一個歸檔庫來執行,以將已完成的段檔案複製到需要的位置。這可能很簡單,就像使用cp
的 shell 命令一樣,或者可以呼叫複雜的 C 函式 — 一切都取決於您。
要啟用 WAL 歸檔,請將 wal_level 配置引數設定為 replica
或更高,將 archive_mode 設定為 on
,在 archive_command 配置引數中指定要使用的 shell 命令,或在 archive_library 配置引數中指定要使用的庫。實際上,這些設定將始終放在 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
這將把可歸檔的 WAL 段複製到目錄 /mnt/server/archivedir
。(這是一個示例,並非建議,並且可能在所有平臺上都無法正常工作。)在替換了 %p
和 %f
引數之後,實際執行的命令可能看起來像這樣
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
對於每個新檔案,都會生成一個類似的命令進行歸檔。
PostgreSQL 伺服器執行的使用者將以該使用者的身份執行歸檔命令。由於被歸檔的 WAL 檔案系列實際上包含資料庫中的所有內容,因此您需要確保歸檔資料免受窺探;例如,將資料歸檔到沒有組或世界可讀許可權的目錄中。
歸檔命令成功時退出狀態必須為零,僅當成功時才為零。獲得零結果後,PostgreSQL 將假定檔案已成功歸檔,並將其刪除或回收。但是,非零狀態會告訴PostgreSQL 檔案未歸檔;它會定期重試,直到成功為止。
另一種歸檔方式是使用自定義歸檔模組作為 archive_library
。由於此類模組是用 C
編寫的,因此建立自己的模組可能比編寫 shell 命令需要更多的精力。但是,歸檔模組可能比透過 shell 歸檔更有效率,並且它們可以訪問許多有用的伺服器資源。有關歸檔模組的更多資訊,請參閱 第 49 章。
當歸檔命令因除伺服器關閉過程中使用的 SIGTERM 訊號(或 shell 錯誤且退出狀態大於 125,如命令未找到)而終止,或者歸檔函式發出 ERROR
或 FATAL
時,歸檔程序會中止,並由 postmaster 重新啟動。在這種情況下,失敗不會在 pg_stat_archiver 中報告。
歸檔命令和庫通常應設計為拒絕覆蓋任何預先存在的歸檔檔案。這是一項重要的安全功能,可防止因管理員錯誤(例如將兩個不同伺服器的輸出傳送到同一個歸檔目錄)而破壞您的歸檔。建議測試您提出的歸檔庫,以確保它不會覆蓋現有檔案。
在極少數情況下,PostgreSQL 可能會嘗試重新歸檔之前已歸檔的 WAL 檔案。例如,如果系統在伺服器建立歸檔成功持久記錄之前崩潰,伺服器將在重新啟動後(如果仍啟用歸檔)嘗試再次歸檔該檔案。當歸檔命令或庫遇到預先存在的檔案時,如果 WAL 檔案內容與預先存在的檔案內容相同且預先存在的檔案已完全持久化到儲存中,則應分別返回零狀態或 true
。如果預先存在的檔案內容與要歸檔的 WAL 檔案內容不同,歸檔命令或庫必須分別返回非零狀態或 false
。
上述 Unix 的示例命令透過包含單獨的 test
步驟來避免覆蓋預先存在的歸檔。在某些 Unix 平臺上,cp
具有 -i
等開關,可以用來不那麼冗餘地完成相同的操作,但您不應依賴這些而無需驗證是否返回了正確的退出狀態。(特別是,GNU cp
在使用 -i
且目標檔案已存在時將返回零狀態,這不是期望的行為。)
在設計您的歸檔設定時,請考慮如果歸檔命令或庫因需要操作員干預的某些方面或歸檔空間不足而反覆失敗會發生什麼。例如,如果您在沒有自動換盤器的情況下寫入磁帶,可能會發生這種情況;當磁帶填滿時,在磁帶更換之前,將無法進行任何進一步的歸檔。您應該確保任何錯誤條件或對人工操作員的請求都得到適當的報告,以便情況能夠儘快得到解決。pg_wal/
目錄將繼續用 WAL 段檔案填充,直到情況得到解決。(如果包含 pg_wal/
的檔案系統已滿,PostgreSQL 將執行 PANIC 關機。不會丟失已提交的事務,但資料庫將保持離線狀態,直到您釋放一些空間。)
只要歸檔命令或庫能夠跟上伺服器生成 WAL 資料的平均速率,其速度就不重要。即使歸檔過程稍有落後,正常操作也會繼續。如果歸檔嚴重落後,這將增加在發生災難時會丟失的資料量。它也意味著 pg_wal/
目錄將包含大量尚未歸檔的段檔案,這些檔案最終可能會超出可用磁碟空間。建議您監控歸檔過程,以確保其按預期工作。
在編寫歸檔命令或庫時,您應該假定要歸檔的檔名最多可以為 64 個字元長,並且可以包含任何 ASCII 字母、數字和點的組合。不必保留原始相對路徑(%p
),但必須保留檔名(%f
)。
請注意,雖然 WAL 歸檔允許您恢復對PostgreSQL 資料庫中資料的任何修改,但它不會恢復對配置檔案(即 postgresql.conf
、pg_hba.conf
和 pg_ident.conf
)所做的更改,因為這些是透過手動編輯而不是透過 SQL 操作完成的。您可能希望將配置檔案儲存在一個位置,該位置將透過您的常規檔案系統備份過程進行備份。有關如何重新定位配置檔案的資訊,請參閱 19.2 節。
歸檔命令或函式僅在已完成的 WAL 段上呼叫。因此,如果您的伺服器產生的 WAL 流量很少(或有低谷期),則從事務完成到安全記錄在歸檔儲存中可能存在很長的延遲。為了限制未歸檔資料的最長保留時間,您可以設定 archive_timeout 來強制伺服器至少以此頻率切換到新的 WAL 段檔案。請注意,由於強制切換而提前歸檔的檔案仍然與完整填充的檔案相同。因此,不建議設定非常短的 archive_timeout
— 它會膨脹您的歸檔儲存。一分鐘左右的 archive_timeout
設定通常是合理的。
此外,您可以透過 pg_switch_wal
手動強制切換段,以確保剛完成的事務儘快歸檔。有關 WAL 管理的其他實用程式函式列在 表 9.97 中。
當 wal_level
為 minimal
時,一些 SQL 命令會被最佳化以避免 WAL 日誌記錄,如 14.4.7 節中所述。如果在執行這些語句期間啟用了歸檔或流複製,WAL 將不會包含足夠的資訊來進行歸檔恢復。(崩潰恢復不受影響。)因此,wal_level
只能在伺服器啟動時更改。但是,archive_command
和 archive_library
可以透過配置檔案過載來更改。如果您透過 shell 進行歸檔並希望暫時停止歸檔,一種方法是將 archive_command
設定為空字串(''
)。這將導致 WAL 檔案在 pg_wal/
中累積,直到重新建立可用的 archive_command
。
執行基礎備份的最簡單方法是使用 pg_basebackup 工具。它可以建立常規檔案形式或 tar 歸檔形式的基礎備份。如果需要比 pg_basebackup 更大的靈活性,您還可以使用低階 API 建立基礎備份(參見 25.3.4 節)。
不必擔心建立基礎備份所需的時間。但是,如果您通常以停用 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 透過指定 --incremental
選項來建立增量備份。您必須將引數 --incremental
提供給早先來自同一伺服器的備份的備份清單。在生成的備份中,非關係檔案將完整包含,但某些關係檔案可能會被替換為較小的增量檔案,其中僅包含自前一個備份以來已更改的塊以及重構檔案當前版本所需的元資料。
為了確定哪些塊需要備份,伺服器使用 WAL 摘要,這些摘要儲存在資料目錄中,位於 pg_wal/summaries
目錄下。如果所需的摘要檔案不存在,嘗試建立增量備份將失敗。此目錄中的摘要必須涵蓋從前一個備份的開始 LSN 到當前備份的開始 LSN 的所有 LSN。由於伺服器在建立當前備份的開始 LSN 後會查詢 WAL 摘要,因此必要的摘要檔案可能不會立即出現在磁碟上,但伺服器會等待任何丟失的檔案出現。這也適用於 WAL 摘要過程落後的情況。但是,如果必要的已刪除檔案,或者 WAL 摘要器未足夠快地趕上,則增量備份將失敗。
恢復增量備份時,不僅需要增量備份本身,還需要所有先前的備份,這些備份對於提供增量備份中省略的塊至關重要。有關此要求的更多資訊,請參閱 pg_combinebackup。請注意,當叢集的校驗和狀態發生更改時,pg_combinebackup
的使用受到限制;請參閱 pg_combinebackup 限制。
請注意,使用完整備份的所有要求同樣適用於增量備份。例如,您仍然需要檔案系統備份期間和之後生成的所有 WAL 段檔案以及任何相關的 WAL 歷史檔案。並且您仍然需要建立 recovery.signal
(或 standby.signal
)並執行恢復,如 25.3.5 節中所述。在恢復時需要早期備份可用並使用 pg_combinebackup
是除了所有其他要求之外的附加要求。請記住,PostgreSQL 沒有內建機制來確定哪些備份仍然是恢復後期增量備份的基礎。您必須自己跟蹤完整備份和增量備份之間的關係,並確保在可能需要時不要刪除早期備份以用於恢復後期增量備份。
增量備份通常只對相對較大的資料庫有意義,其中大部分資料不更改或更改緩慢。對於小型資料庫,忽略增量備份的存在並簡單地進行完整備份更簡單,後者更容易管理。對於大量資料都頻繁修改的大型資料庫,增量備份的大小不會比完整備份小多少。
僅當重放的起始檢查點晚於其依賴的前一個備份時,才可能進行增量備份。如果您在主伺服器上進行增量備份,則此條件始終滿足,因為每次備份都會觸發新的檢查點。在備用伺服器上,重放從最近的重啟點開始。因此,如果自上一個備份以來活動很少,備用伺服器的增量備份可能會失敗,因為可能沒有建立新的重啟點。
與其使用 pg_basebackup 來建立完整或增量基礎備份,不如使用低階 API。此過程比 pg_basebackup 方法多一些步驟,但相對簡單。非常重要的是,這些步驟必須按順序執行,並且在進行下一步之前要驗證前一步的成功。
可以併發執行多個備份(包括透過此備份 API 和透過 pg_basebackup 啟動的備份)。
確保 WAL 歸檔已啟用且正常工作。
以具有執行 pg_backup_start
許可權的使用者(超級使用者,或已授予該函式 EXECUTE
許可權的使用者)連線到伺服器(資料庫無所謂),然後發出命令
SELECT pg_backup_start(label => 'label', fast => false);
其中 label
是您要用於唯一標識此備份操作的任意字串。呼叫 pg_backup_start
的連線必須一直保持到備份結束,否則備份將被自動中止。
線上備份始終在檢查點開始時啟動。預設情況下,pg_backup_start
會等待下一個計劃中的檢查點完成,這可能需要很長時間(請參閱配置引數 checkpoint_timeout 和 checkpoint_completion_target)。這通常是首選,因為它最大程度地減少了對正在執行的系統的影響。如果您希望儘快開始備份,請將 true
作為第二個引數傳遞給 pg_backup_start
,它將請求立即進行檢查點,該檢查點將盡快完成,並儘可能多地使用 I/O。
使用任何方便的檔案系統備份工具(如 tar 或 cpio)(而不是 pg_dump 或 pg_dumpall)執行備份。在此期間,既不需要也不希望停止資料庫的正常執行。有關在此備份期間需要考慮的事項,請參閱 25.3.4.1 節。
在與之前相同的連線中,發出命令
SELECT * FROM pg_backup_stop(wait_for_archive => true);
這將終止備份模式。在主伺服器上,它還會自動切換到下一個 WAL 段。在備用伺服器上,無法自動切換 WAL 段,因此您可能希望在主伺服器上執行 pg_switch_wal
來執行手動切換。切換的原因是為了準備在備份期間寫入的最後一個 WAL 段檔案進行歸檔。
pg_backup_stop
將返回一行,其中包含三個值。其中第二個欄位應寫入備份根目錄下的名為 backup_label
的檔案中。第三個欄位應寫入名為 tablespace_map
的檔案中,除非該欄位為空。這些檔案對備份的正常工作至關重要,並且必須逐字無修改地寫入,這可能需要以二進位制模式開啟檔案。
一旦備份期間活動的 WAL 段檔案被歸檔,您就完成了。由 pg_backup_stop
的第一個返回值標識的檔案是構成完整備份檔案集所需的最後一個段。在主伺服器上,如果啟用了 archive_mode
並且 wait_for_archive
引數為 true
,則 pg_backup_stop
在最後一個段已歸檔之前不會返回。在備用伺服器上,archive_mode
必須為 always
才能使 pg_backup_stop
等待。這些檔案的歸檔是自動發生的,因為您已經配置了 archive_command
或 archive_library
。在大多數情況下,這會很快發生,但建議您監控歸檔系統,以確保沒有延遲。如果由於歸檔命令或庫失敗而導致歸檔程序落後,它將繼續重試,直到歸檔成功並且備份完成。如果您希望為 pg_backup_stop
的執行設定時間限制,請設定適當的 statement_timeout
值,但請注意,如果 pg_backup_stop
因此而終止,則您的備份可能無效。
如果備份過程監視並確保備份所需的所有 WAL 段檔案都已成功歸檔,則可以將 wait_for_archive
引數(預設為 true)設定為 false,使 pg_backup_stop
在寫入停止備份記錄到 WAL 後立即返回。預設情況下,pg_backup_stop
會等待所有 WAL 都歸檔完畢,這可能需要一段時間。此選項必須謹慎使用:如果 WAL 歸檔未被正確監視,則備份可能不包含所有 WAL 檔案,因此不完整,無法恢復。
一些檔案系統備份工具在複製它們正在嘗試複製的檔案時如果檔案發生更改,會發出警告或錯誤。在活動資料庫上建立基礎備份時,這種情況是正常的,而不是錯誤。但是,您需要確保能夠區分此類抱怨和真正錯誤。例如,某些版本的 rsync 會為“消失的原始檔”返回單獨的退出程式碼,您可以編寫一個驅動程式指令碼來接受此退出程式碼作為非錯誤情況。另外,某些版本的 GNU tar 在檔案在複製過程中被更改時會返回一個與致命錯誤無法區分的錯誤程式碼。幸運的是,GNU tar 版本 1.16 及更高版本在檔案在備份過程中發生更改時退出程式碼為 1,而對於其他錯誤則為 2。使用 GNU tar 版本 1.23 及更高版本,您可以使用警告選項 --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/
目錄下的檔案,這樣主伺服器上存在的複製槽就不會成為備份的一部分。否則,後續使用備份建立備用伺服器可能會導致備用伺服器上 WAL 檔案的無限期保留,並且如果啟用了熱備用反饋,主伺服器上可能會出現膨脹,因為使用這些複製槽的客戶端仍然會連線並更新主伺服器上的槽,而不是備用伺服器上的槽。即使備份僅用於建立新的主伺服器,複製槽的內容在新的主伺服器上線時很可能已經過時,因此複製它們並不特別有用。
可以從備份中省略 pg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
和 pg_subtrans/
(但不是目錄本身)中的檔案,因為它們將在 postmaster 啟動時進行初始化。
任何以 pgsql_tmp
開頭的檔案或目錄都可以從備份中省略。這些檔案在 postmaster 啟動時會被刪除,目錄會在需要時重新建立。
pg_internal.init
檔案可以在找到同名檔案時從備份中省略。這些檔案包含關係快取資料,這些資料在恢復時總是會重新構建。
備份標籤檔案包含您傳遞給 pg_backup_start
的標籤字串,以及 pg_backup_start
執行的時間,以及起始 WAL 檔案的名稱。因此,在混淆的情況下,可以檢視備份檔案並確定轉儲檔案來自哪個備份會話。表空間對映檔案包含 pg_tblspc/
目錄中的符號連結名稱以及每個符號連結的完整路徑。這些檔案不僅僅是為了您的資訊;它們的存在和內容對於系統的恢復過程的正常執行至關重要。
也可以在伺服器停止時進行備份。在這種情況下,您顯然不能使用 pg_backup_start
或 pg_backup_stop
,因此您需要自行跟蹤哪個備份是哪個以及相關的 WAL 檔案回溯到哪裡。通常最好遵循上面的連續歸檔過程。
好了,最壞的情況已經發生,您需要從備份中恢復。以下是過程
如果伺服器正在執行,請停止它。
如果您有足夠的空間,請將整個叢集資料目錄和任何表空間複製到臨時位置,以備將來需要。請注意,此預防措施要求您的系統有足夠的可用空間來容納資料庫的兩個副本。如果您沒有足夠的空間,至少應儲存叢集 pg_wal
子目錄的內容,因為它可能包含系統在崩潰前尚未歸檔的 WAL 檔案。
刪除叢集資料目錄下的所有現有檔案和子目錄,以及您正在使用的任何表空間根目錄下的檔案和子目錄。
如果您正在恢復完整備份,您可以將資料庫檔案直接恢復到目標目錄。確保它們以正確的使用者(資料庫系統使用者,而不是 root
!)和正確的許可權進行恢復。如果您正在使用表空間,您應該驗證 pg_tblspc/
中的符號連結是否已正確恢復。
如果您正在恢復增量備份,您將需要將增量備份以及它直接或間接依賴的所有早期備份恢復到您正在執行恢復的機器上。這些備份需要放置在單獨的目錄中,而不是您希望正在執行的伺服器最終所在的目錄。完成後,使用 pg_combinebackup 從完整備份以及所有後續增量備份中提取資料,並將合成的完整備份寫入目標目錄。如上所述,驗證許可權和表空間連結是否正確。
刪除 pg_wal/
中存在的任何檔案;這些檔案來自檔案系統備份,因此可能已過時而不是最新的。如果您根本沒有歸檔 pg_wal/
,則用正確的許可權重新建立它,同時小心確保如果它以前設定為符號連結,則重新建立它。
如果您有未歸檔的 WAL 段檔案(您在步驟 2 中儲存的),請將它們複製到 pg_wal/
。(最好複製而不是移動它們,這樣如果出現問題並且您必須重新開始,您仍然擁有未修改的檔案。)
在 postgresql.conf
中設定恢復配置設定(請參閱 19.5.5 節)並在叢集資料目錄中建立一個 recovery.signal
檔案。您可能還想暫時修改 pg_hba.conf
以防止普通使用者連線,直到您確定恢復成功。
啟動伺服器。伺服器將進入恢復模式,並開始讀取它需要的歸檔 WAL 檔案。如果由於外部錯誤而終止恢復,伺服器可以簡單地重新啟動,它將從失敗點附近繼續恢復。恢復完成後,伺服器將刪除 recovery.signal
(以防止以後意外再次進入恢復模式),然後開始正常資料庫操作。
檢查資料庫內容,確保已恢復到期望的狀態。如果未恢復到期望的狀態,請返回步驟 1。如果一切正常,請透過將 pg_hba.conf
恢復正常來允許使用者連線。
這一切的關鍵部分是設定一個恢復配置,該配置描述了您希望如何恢復以及恢復應該執行多遠。您絕對必須指定的是 restore_command
,它告訴PostgreSQL 如何檢索歸檔的 WAL 檔案段。與 archive_command
類似,這是一個 shell 命令字串。它可以包含 %f
,它將被替換為所需 WAL 檔案的名稱,以及 %p
,它將被替換為 WAL 檔案要複製到的路徑名。(路徑名是相對於當前工作目錄的,即叢集的資料目錄。)如果您需要在命令中嵌入實際的 %
字元,請寫 %%
。最簡單的有用命令是
restore_command = 'cp /mnt/server/archivedir/%f %p'
這將從目錄 /mnt/server/archivedir
複製先前歸檔的 WAL 段。當然,您可以使用更復雜的東西,甚至是一個要求操作員掛載適當磁帶的 shell 指令碼。
命令在失敗時返回非零退出狀態很重要。命令將被呼叫請求不存在於歸檔中的檔案;當被這樣詢問時,它必須返回非零。這不是錯誤條件。例外情況是,如果命令被訊號(除了用作資料庫伺服器關閉一部分的 SIGTERM)或 shell 錯誤(如命令未找到)終止,則恢復將中止,伺服器將不會啟動。
並非所有請求的檔案都將是 WAL 段檔案;您還應該期望請求帶有 .history
字尾的檔案。還要注意 %p
路徑的基本名稱將與 %f
不同;不要期望它們可以互換。
在歸檔中找不到的 WAL 段將在 pg_wal/
中查詢;這允許使用最近未歸檔的段。但是,從歸檔中可用的段將優先於 pg_wal/
中的檔案。
通常,恢復將透過所有可用的 WAL 段進行,從而將資料庫恢復到當前時間點(或儘可能接近,考慮到可用的 WAL 段)。因此,正常恢復將以 “檔案未找到” 訊息結束,錯誤訊息的確切文字取決於您選擇的 restore_command
。您還可能在恢復開始時看到關於名為 00000001.history
的檔案的錯誤訊息。這在簡單恢復情況下也是正常的,並且不表示有問題;有關討論,請參閱 25.3.6 節。
如果您想恢復到某個較早的時間點(例如,就在初級 DBA 刪除您的主要事務表之前),只需指定所需的 停止點。您可以按日期/時間、命名恢復點或特定事務 ID 的完成來指定停止點,稱為“恢復目標”。截至本文撰寫時,只有日期/時間和命名恢復點選項非常實用,因為沒有工具可以幫助您準確地識別要使用的事務 ID。
停止點必須晚於基礎備份的結束時間,即 pg_backup_stop
的結束時間。您不能使用基礎備份恢復到該備份正在進行的某個時間點。(要恢復到該時間點,您必須回溯到上一個基礎備份並從那裡向前滾動。)
如果恢復發現損壞的 WAL 資料,恢復將在該點停止,並且伺服器將不會啟動。在這種情況下,可以從頭開始重新執行恢復過程,指定一個“恢復目標”,該目標位於損壞點之前,以便恢復可以正常完成。如果由於外部原因(如系統崩潰或 WAL 歸檔不可訪問)而恢復失敗,則可以簡單地重新啟動恢復,它將從失敗點附近重新啟動。恢復重啟的工作方式與正常操作中的檢查點類似:伺服器定期將所有狀態強制寫入磁碟,然後更新 pg_control
檔案,以指示無需再次掃描已處理的 WAL 資料。
將資料庫恢復到先前的某個時間點的能力會產生一些複雜的、類似於科幻故事中的時間旅行和並行宇宙。例如,在資料庫的原始歷史中,假設您在星期二晚上 5:15 刪除了一個關鍵表,但直到週三中午才意識到錯誤。您不慌不忙,拿出備份,恢復到星期二晚上 5:14 的時間點,然後啟動並執行。在資料庫宇宙的這個歷史中,您從未刪除過該表。但是,如果您後來意識到這不是一個好主意,並希望回到原始歷史中的週三早上某個時間點,那麼當您的資料庫執行時,它會覆蓋導致您現在希望能夠回溯的時間點的某些 WAL 段檔案,您將無法返回。因此,為了避免這種情況,您需要區分在進行時間點恢復後生成的 WAL 記錄系列與原始資料庫歷史中生成的 WAL 記錄系列。
為了解決這個問題,PostgreSQL 有一個時間線的概念。每當完成歸檔恢復時,就會建立一個新的時間線來標識該恢復後生成的 WAL 記錄系列。時間線 ID 號是 WAL 段檔名的一部分,因此新時間線不會覆蓋先前時間線生成的 WAL 資料。例如,在 WAL 檔名 0000000100001234000055CD
中,前面的 00000001
是十六進位制的時間線 ID。(請注意,在其他上下文中,例如伺服器日誌訊息,時間線 ID 通常以十進位制列印。)
實際上可以歸檔許多不同的時間線。雖然這可能看起來是一個無用的功能,但它通常是救命稻草。考慮這種情況:您不確定要恢復到哪個時間點,因此必須透過試錯進行幾次時間點恢復,直到找到最佳的從舊歷史分支的點。沒有時間線,這個過程很快就會產生一個難以管理的混亂。有了時間線,您可以恢復到任何先前狀態,包括您早期放棄的時間線分支中的狀態。
每次建立新時間線時,PostgreSQL 都會建立一個“時間線歷史”檔案,顯示它從哪個時間線分支以及何時分支。這些歷史檔案對於系統在從包含多個時間線的歸檔中恢復時選擇正確的 WAL 段檔案是必需的。因此,它們像 WAL 段檔案一樣被歸檔到 WAL 歸檔區域。歷史檔案只是小的文字檔案,因此保留它們是便宜且合適的(不像段檔案那樣大)。如果您願意,可以在歷史檔案中添加註釋,記錄您自己關於為何以及如何建立該特定時間線的筆記。當您由於實驗而產生大量不同的時間線時,此類註釋將特別有價值。
恢復的預設行為是恢復到歸檔中找到的最新時間線。如果您希望恢復到基礎備份建立時的當前時間線或恢復到特定的子時間線(即,您想回到本身是在恢復嘗試後生成的某個狀態),則需要在 recovery_target_timeline 中指定 current
或目標時間線 ID。您不能恢復到比基礎備份更早分支的時間線。
此處提供了一些配置連續歸檔的技巧。
可以使用PostgreSQL 的備份功能來生成獨立的線上備份。這些備份不能用於時間點恢復,但通常比 pg_dump 轉儲備份和恢復速度快得多。(它們也比 pg_dump 轉儲大得多,因此在某些情況下速度優勢可能會被抵消。)
與基礎備份一樣,生成獨立線上備份的最簡單方法是使用 pg_basebackup 工具。如果您在呼叫它時包含 -X
引數,則使用備份所需的所有預寫日誌將自動包含在備份中,並且恢復備份不需要特殊操作。
如果歸檔儲存大小是一個問題,您可以使用 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 時,這可能是不希望的。即使在同一臺機器上重放 WAL,但重放到新的資料目錄時,這也可能很危險:重放仍將覆蓋原始表空間的*.內容。為避免此類潛在的陷阱,最佳做法是在建立或刪除表空間後進行新的基礎備份。
還應注意,預設的WAL格式由於包含許多磁碟頁面快照而相當龐大。這些頁面快照旨在支援崩潰恢復,因為我們可能需要修復部分寫入的磁碟頁面。根據您的系統硬體和軟體,忽略部分寫入的風險可能很小,在這種情況下,您可以透過關閉頁面快照(使用 full_page_writes 引數)來顯著減少歸檔 WAL 檔案的總量。(在此之前,請閱讀 第 28 章 中的說明和警告。)關閉頁面快照不會阻止 WAL 用於 PITR 操作。未來的開發領域是壓縮歸檔 WAL 資料,即使 full_page_writes
處於開啟狀態,也可以透過刪除不必要的頁面副本。在此期間,管理員可能希望透過儘可能增加檢查點間隔引數來減少 WAL 中包含的頁面快照數量。
如果您在文件中發現任何不正確之處、與您在特定功能上的體驗不符之處或需要進一步澄清之處,請使用 此表格 報告文件問題。