Categories
Database Backup

**

對於管理生產環境 PostgreSQL 的資料庫管理員 (DBA) 和 DevOps 工程師而言,實現近乎零的復原點目標 (RPO) 是一項首要任務。PostgreSQL 的災難復原與時間點復原 (PITR) 能力的核心在於預寫式記錄 (Write-Ahead Logging, WAL)。雖然 WAL 透過在將交易寫入資料檔案之前先進行記錄來確保 ACID 合規性,但 WAL 歸檔 (archiving) 才是將這些記錄保存以供長期備份與複製的機制。

然而,配置 WAL 歸檔並非「設定好就不用管」的操作。錯誤的配置、無聲的失敗以及對架構的誤解,都可能導致災難性的資料遺失、腦裂 (split-brain) 場景或完整的資料庫中斷。

在本綜合指南中,我們將探討 PostgreSQL WAL 歸檔的架構,找出導致資料遺失的最常見陷阱,並概述生產級的最佳實踐,以確保您的資料庫保持彈性。

了解 PostgreSQL WAL 架構

在深入探討陷阱之前,了解 PostgreSQL 如何處理交易記錄至關重要。

PostgreSQL 將所有修改寫入位於 pg_wal 目錄(版本 10 之前稱為 pg_xlog)中的 WAL 區段(預設為 16MB 檔案)。每筆交易都會按順序記錄,並由記錄序號 (LSN) 標記。

當 WAL 區段填滿時,PostgreSQL 會切換到新的區段。為了防止 pg_wal 目錄無限增長,PostgreSQL 會在不再需要用於崩潰復原或複製時,回收或刪除舊的 WAL 區段。

WAL 歸檔會攔截此回收過程。當啟用 archive_mode 時,PostgreSQL 會執行使用者定義的 archive_command(或在 PostgreSQL 15+ 中使用 archive_library),將已完成的 WAL 區段複製到安全的次要位置,然後才將其刪除或覆寫。

要執行時間點復原 (PITR),您需要兩個組件:
1. 有效的基礎備份。
2. 從基礎備份時間點到目標復原時間點之間,不中斷的歸檔 WAL 檔案鏈。

如果該 WAL 鏈中斷,您的 PITR 就會失敗。

為生產環境配置 WAL 歸檔

要啟用 WAL 歸檔,您必須修改 postgresql.conf 檔案。基本配置需要設定 wal_level、啟用 archive_mode 並定義 archive_command

# postgresql.conf
wal_level = replica             # 歸檔需要 'replica' 或 'logical'
archive_mode = on               # 啟用歸檔程序
archive_command = 'test ! -f /mnt/nfs/archive/%f && cp %p /mnt/nfs/archive/%f'
archive_timeout = 600           # 強制每 10 分鐘進行一次 WAL 切換

archive_command 中:
* %p 代表要歸檔的 WAL 檔案完整路徑。
* %f 代表 WAL 檔案的檔名。

雖然上述配置看起來很簡單,但在企業環境中依賴簡單的 shell 指令會帶來重大風險。

WAL 歸檔中的常見陷阱

陷阱 1:archive_command 的「無聲成功」

PostgreSQL 完全依賴 archive_command 的退出代碼。如果指令返回 0,PostgreSQL 就會假設 WAL 檔案已安全歸檔,並繼續回收原始檔案。

一個常見的錯誤是使用即使資料未安全刷新到永久儲存裝置也會返回 0 的指令。例如,簡單的 cp 指令可能在資料到達目的地伺服器的作業系統頁面快取 (page cache) 時就返回成功。如果目的地伺服器在快取刷新到磁碟之前斷電,WAL 檔案就會遺失,但 PostgreSQL 已經刪除了其本機副本。

風險: WAL 鏈中斷且無法執行 PITR,這通常只有在災難復原場景中才會被發現。

緩解措施: 確保您的歸檔指令碼強制執行同步寫入。如果使用標準 shell 指令,請利用能保證資料已刷新的工具,或編寫一個在傳輸後驗證檔案大小與校驗和的包裝指令碼。

陷阱 2:pg_wal 分割區耗盡 (WAL 膨脹)

如果 archive_command 失敗(返回非零退出代碼)——由於網路中斷、權限錯誤或目的地磁碟已滿——PostgreSQL 將保留 pg_wal 目錄中的 WAL 檔案並無限期地重試該指令。

雖然這透過不刪除未歸檔的 WAL 來防止資料遺失,但它引入了嚴重的可用性風險。如果 pg_wal 目錄所在的分割區填滿至 100%,PostgreSQL 將發出 PANIC 並崩潰。除非釋放空間,否則資料庫將無法再次啟動。

風險: 由於 pg_wal 分割區已滿而導致資料庫完全停機。

緩解措施:
1. 始終將 pg_wal 放置在專用的磁碟分割區上。
2. 對 pg_wal 目錄大小實施嚴格監控。
3. 監控 pg_stat_archiver 檢視,以便立即偵測失敗的歸檔指令。

陷阱 3:不完整的基礎備份

如果沒有備份過程中產生的 WAL 檔案,基礎備份就毫無用處。如果您進行檔案系統層級的快照,或在不串流 WAL 的情況下使用 pg_basebackup (-X stream),則必須確保備份開始與結束之間產生的 WAL 檔案已成功歸檔。

如果您的歸檔程式滯後或失敗,且那些特定的 WAL 檔案遺失,則基礎備份將無法達到一致狀態。

風險: 損壞或無法復原的基礎備份。

緩解措施: 使用 pg_basebackup -X stream 將必要的 WAL 檔案包含在備份負載中,或利用自動管理基礎備份與 WAL 區段之間依賴關係的企業級備份解決方案。

陷阱 4:時間軸混亂與腦裂場景

當備用伺服器被提升為主伺服器時,PostgreSQL 會增加「時間軸 ID」(WAL 檔名的第一部分,例如 0000000200000001000000A4)。這可以防止新的主伺服器覆寫舊主伺服器的 WAL 歷史記錄。

然而,如果舊的主伺服器在未正確隔離的情況下意外啟動(腦裂場景),它可能會嘗試使用舊的時間軸將 WAL 檔案推送到相同的歸檔位置。如果您的 archive_command 盲目地覆寫檔案,您可能會損壞您的歸檔儲存庫。

風險: WAL 檔案被覆寫、歸檔損壞以及資料庫無法復原。

緩解措施: 您的 archive_command 絕對不能覆寫現有檔案。請注意,在前面的基本配置中,我們使用了 test ! -f /mnt/nfs/archive/%f,以便在檔案已存在時明確失敗。

緩解資料遺失風險:生產環境最佳實踐

為了強化您的 PostgreSQL 歸檔策略,請實施以下最佳實踐。

1. 原生監控歸檔程序

PostgreSQL 提供了一個內建檢視 pg_stat_archiver,用於追蹤歸檔程序的成功與失敗。您應該將此檢視整合到您的可觀測性堆疊中(例如 Prometheus、Datadog 或 Zabbix)。

SELECT 
    archived_count,
    last_archived_wal,
    last_archived_time,
    failed_count,
    last_failed_wal,
    last_failed_time,
    stats_reset
FROM pg_stat_archiver;

需配置的警報閾值:
* 如果 failed_count 增加,則發出警報。
* 如果 now()last_archived_time 之間的時間差超過您的 RPO 閾值(例如 15 分鐘),則發出警報,請記住,除非設定了 archive_timeout,否則低流量資料庫可能會自然產生延遲。

2. 利用 archive_timeout

在寫入量較低的資料庫中,一個 16MB 的 WAL 檔案可能需要數小時才能填滿。在填滿之前,它不會被歸檔。如果伺服器崩潰且本機磁碟遺失,您將遺失數小時的交易。

設定 archive_timeout = 600 (10 分鐘) 會強制 PostgreSQL 切換到新的 WAL 檔案並歸檔目前的檔案,即使它尚未填滿。這保證了您的 RPO 不會超過 10 分鐘,代價是因部分填滿的 WAL 檔案而導致儲存空間使用量略微增加。

3. 轉換至 archive_library (PostgreSQL 15+)

過去,archive_command 會為每個 WAL 檔案產生一個新的 shell 程序。在高吞吐量環境中,每分鐘產生數百個 WAL 檔案,產生 shell 程序的開銷會成為效能瓶頸。

PostgreSQL 15 引入了 archive_library 參數,允許透過動態載入的 C 模組來處理 WAL 歸檔。這消除了 shell 產生的開銷,並提供了更強大、高效能的歸檔機制。如果您使用的是 PostgreSQL 15 或更高版本,請尋找支援自訂歸檔模組的備份工具。

4. 定期測試時間點復原

未經測試的備份不是備份;那只是一個願望。驗證您的 WAL 歸檔功能是否正常、WAL 鏈是否未中斷以及基礎備份是否一致的唯一方法,就是執行例行性的自動化 PITR 測試。

啟動一個臨時執行個體,還原基礎備份,配置 restore_command 以從您的歸檔中提取資料,並復原到特定的時間戳記。驗證資料庫是否達到一致狀態並開放連線。

使用 CloudSave 進行企業級備份與復原

管理 archive_command 的自訂 shell 指令碼、處理 WAL 去重以及確保交易記錄的安全異地儲存,很快會成為 IT 團隊的營運負擔。

這正是 CloudSave 為企業級 PostgreSQL 環境提供重大價值的地方。CloudSave 直接與 PostgreSQL 的原生備份與 WAL 歸檔 API 整合,以消除上述手動操作的陷阱。

CloudSave 不再需要編寫脆弱的 bash 指令碼,而是提供了一種強大的、基於代理程式或無代理程式的整合,能夠:
* 保證交付: 以經過驗證、校驗和確認的傳輸方式取代標準 shell 指令,傳輸至安全的異地或雲端儲存空間。
* 防止 WAL 膨脹: 主動監控 pg_wal 目錄,並在分割區耗盡前很久就向管理員發出警報。
* 自動化 PITR: 透過直覺的介面簡化時間點復原。您只需選擇想要復原到的精確分鐘,CloudSave 就會自動擷取正確的基礎備份,並串流達到該狀態所需的精確 WAL 檔案序列。
* 處理時間軸: 智慧管理 PostgreSQL 時間軸歷史記錄,確保故障轉移和腦裂場景不會損壞您的備份儲存庫。

透過將 WAL 管理的繁重工作卸載給 CloudSave,DBA 可以專注於查詢最佳化與資料庫效能,並確信其 RPO 與 RTO SLA 受到企業級平台的保護。

結論

PostgreSQL WAL 歸檔是資料庫災難復原的骨幹。雖然將檔案從一個目錄複製到另一個目錄的概念看起來很簡單,但邊緣情況(無聲失敗、磁碟耗盡和時間軸分歧)對資料完整性構成了嚴重風險。

透過了解 pg_wal 的架構、嚴格避免破壞性的 archive_command 配置、監控 pg_stat_archiver 以及利用像 CloudSave 這樣的企業級備份平台,您可以建立一個具備彈性的 PostgreSQL 基礎架構,能夠在硬體故障、人為錯誤和災難性中斷中存活,而不會遺失任何一筆已提交的交易。

探索導致資料遺失的常見 PostgreSQL WAL 歸檔陷阱。學習專家 DBA 的最佳實踐、配置技巧,以及如何為企業級資料庫確保可靠的時間點復原 (PITR)。