從 資料寫入、WAL 生成、日誌切換 (Switching)、歸檔 (Archive) 到 備份 (Backup) 的完整生命週期:
1. 資料寫入與 WAL 生成 (Data Writing & WAL Generation)
這是資料誕生的第一步,核心原則是「先記帳,後結帳」 (Write-Ahead Logging)**。
- 寫入緩衝區: 當您執行
INSERT或UPDATE等指令時,PostgreSQL 不會立刻修改硬碟上的資料庫主檔案(Data Files),而是先將這筆異動記錄到記憶體中的 WAL Buffer。 - 強制落盤 (Flush): 當交易提交 (Commit) 時,這條日誌必須立刻被寫入硬碟中
pg_wal資料夾下的 WAL Segment 檔案。 - 確保安全性: 只要這條日誌進入了
pg_wal,即便下一秒斷電,資料庫重啟後也能透過重播日誌找回資料。 - 檢查點 (Checkpoint): 只有在 Checkpoint 發生時,記憶體中實際修改的數據(Dirty Buffers)才會真正寫入資料庫的主檔案。此時,舊的 WAL 就不再需要用於崩潰恢復。
2. 日誌切換與管理 (WAL Switching & Management)
WAL 檔案並不是無限寫在同一個檔案裡,而是有固定大小與輪替機制的。
- 切換機制 (Switching): 預設每個 WAL 檔案大小為 16MB。當一個檔案寫滿時,PostgreSQL 會進行「切換」,開始寫入下一個序號的檔案。
- 回收與重命名 (Recycling): 為了節省建立新檔案的 I/O 開銷,PostgreSQL 會將不再需要的舊 WAL 檔案(已過 Checkpoint 且已歸檔者)重新命名為未來的序號,循環使用。
- 刪除機制: 如果
pg_wal累積的數量超過設定範圍(如max_wal_size),且確認已歸檔完成,系統才會物理刪除多餘的檔案。
3. 歸檔傳送 (Archiving)
這是將資料從「本地暫存」轉移到「外部保險箱」的關鍵步驟,由 pgBackRest 擔任搬運工。
- 觸發傳送: 一旦 WAL 發生「日誌切換 (Switching)」(即寫滿 16MB),PostgreSQL 會立刻執行
archive_command。 - 搬運與壓縮:
archive_command會呼叫pgbackrest archive-push。pgBackRest 會將該 WAL 檔案進行壓縮,並傳送到遠端的儲存庫(Repo)。 - 形成連續鏈: 這些歸檔後的 WAL 檔案在 Repo 中依序號排列,只要鏈條不斷,您就擁有從過去到現在的所有變動紀錄。
- 空窗期風險: 值得注意的是,正在寫入但「還沒寫滿 16MB」的那個 WAL 檔案,通常還不會被傳送到 Archive。如果此時硬碟全毀,這最後一小段資料可能會遺失,除非您設定了
archive_timeout強制切換。
4. 備份快照 (Backup)
歸檔是「錄影帶」,備份則是「全家福照片」。單靠重播日誌太慢,需要定期建立基礎還原點。
- 全量備份 (Full Backup): pgBackRest 會拷貝所有的數據主檔案 (Data Files)。這就像拍下一張建築物的完整照片。
- 建立關聯: 備份完成的那一刻,pgBackRest 會記錄這份備份對應到的 WAL 序號,確立還原時的起點。
- 差異與增量: 為了節省空間,之後的備份可以只抓取自上次全備份以來有變動的檔案 (Diff/Incr)。
5. 流程總結與隱喻
為了讓這個複雜的流程更容易記憶,我們可以套用之前提到的隱喻:
| 階段 | 動作 | 隱喻說明 | 關鍵行為 |
|---|---|---|---|
| 1. 寫入 | WAL Generation | 施工日記 | 師傅每砌一塊磚,先在隨身筆記本(記憶體)寫下,然後立刻抄寫到現場日誌本(pg_wal)上。 |
| 2. 切換 | Switching | 換新本子 | 現場日誌本寫滿了(16MB),師傅換一本新的繼續寫,舊的本子準備封存。 |
| 3. 歸檔 | Archive | 送往檔案室 | 搬運工(pgBackRest)立刻把寫滿的舊本子拿走,壓縮打包送去遠處的防火檔案室(Repo)。 |
| 4. 備份 | Backup | 拍攝全景照 | 攝影師每週來一次,拍下整棟建築物目前的樣子(Data Files)。這樣下次要重建時,就不用從打地基開始看日記,直接看照片再補日記即可。 |
特別提醒: 在災難還原時,如果原始機器的 pg_wal 硬碟沒壞,務必手動將那些「還沒來得及歸檔」的 WAL 檔案拷貝出來,並在還原後放回新機器,這樣才能達成真正的 Zero Data Loss(零資料遺失)。