你在用資料庫的時候,感覺一切都很簡單:加一行、更新一筆、刪掉一個客戶。但這背後其實藏著一套很複雜又設計精良的機制。那些資料到底存在哪?PostgreSQL 怎麼做到就算伺服器突然斷電也不會掉資料?
要搞懂這些,你得先知道兩個重點:資料(table、index、系統資訊)實際上放在哪裡,還有資料保護機制怎麼運作——也就是交易日誌,WAL(Write-Ahead Logging)。
整個 PostgreSQL 資料庫其實就是一堆檔案,放在一個特定的資料夾裡——data_directory。通常會在這裡:
/var/lib/postgresql/17/main
這個資料夾就是資料庫的心臟:table、index、meta 資訊、設定檔全都在這。WAL 日誌也在這裡——這個機制會最先收到所有變更。資料還沒寫進 table 檔案前,會先寫進 WAL。這就像草稿本,資料庫會把每一步都記下來,萬一出事就能還原到最後一個操作。
靠這種設計,PostgreSQL 就算遇到很不穩的狀況也能保證資料安全跟穩定。
Table
每個 table 實際上就是一個獨立檔案或一組檔案。這些檔案會放在 base/ 子目錄。結構大概長這樣:
$PGDATA/base/
├── 16384/
│ ├── 12345 ← 資料表
│ ├── 12346 ← 索引
│ └── ...
16384— 這是資料庫的內部 ID(OID)。12345— 這是某個 table 的 ID。
如果 table 很大,PostgreSQL 會把它切成 1GB 的 segment:
12345
12345.1
12345.2
...
這些檔案不是像 CSV 那樣存「一行一行」的文字——而是 8KB 的「二進位 page」格式。
WAL: Write-Ahead Logging 不是普通的「log」
現在來講 PostgreSQL 裡最重要、但常常被誤解的東西——WAL,也就是Write-Ahead Logging。雖然名字裡有 log,但 WAL 不是一般的文字 log 檔,不像 error log 或 query log。它是資料一致性跟還原的關鍵機制,直接在檔案系統的低階層級運作。
WAL 不是事件報告,而是所有變更的預先記錄,PostgreSQL 打算對資料做什麼都會先寫進這裡。這個記錄會在實際改 table 檔案之前就寫好。所以才叫 write-ahead——「先寫再說」。
比如你插入一行新資料,PostgreSQL 會:
- 不會馬上改 table 檔案——這樣太慢也不安全。
- 先寫進 WAL,記下這行要加進去。
- 等到適合的時候(像是 background process),才真的把資料寫進 table。
這就像銀行支票:你先簽名(WAL),銀行之後才會更新帳戶(table)。如果出問題——支票還在,可以重來一次。
WAL 的格式與結構
- WAL 檔案是二進位格式。
- 每個檔案都是嚴格排序的操作流程,描述資料 page、index 結構、commit 等等的內部變更。
- 一個 WAL 檔案大小固定——預設是 16MB。
重點:WAL 裡沒有「SQL 指令」或「table row」這種東西。它存的是PostgreSQL 引擎的指令,教它怎麼一頁一頁還原變更。
如果發生故障會怎樣?
如果 PostgreSQL 伺服器突然掛掉——比如突然斷電——也不用怕。下次啟動時,資料庫不會慌張,而是會從硬碟載入最後一個「穩定」的資料版本。然後它會拿出 WAL 日誌,裡面有所有最近的變更,慢慢「補上」那些還沒寫進主要檔案的東西。最後資料庫就會回到完全一致的狀態,好像什麼事都沒發生過一樣。
WAL 的進階功能
Point-In-Time Recovery (PITR)。 只要有 WAL 檔案,就能把資料庫還原到任意時間點,只要在兩個完整備份之間。
串流複製(Streaming Replication)。 PostgreSQL 可以即時把 WAL 記錄傳到另一台伺服器。這樣就能維護熱備份——跟主資料庫同步的複本。
增量還原(Incremental Recovery)。 配合完整備份,WAL 可以只還原變更的部分,不用整個資料庫重來。
建立二進位備份:pg_basebackup
如果你用過 pg_dump,就知道它很適合做邏輯備份(把資料庫結構跟資料存成 SQL 指令)。但如果你要做物理備份呢?比如要完整鏡像所有資料庫檔案?這時候就要用 pg_basebackup 這個工具了。
pg_basebackup 是個可以建立 PostgreSQL 實體資料複本的工具。對大型資料庫來說,這很方便,還原起來也有效率。pg_basebackup 最大的優點就是超快。
pg_basebackup 的基本指令語法
用 pg_basebackup 前要先搞懂它的指令。你在終端機下這樣打:
pg_basebackup -D /backup_directory -F tar -z -P
來拆解一下:
-D /backup_directory— 指定備份檔要存到哪個資料夾。-F tar— 資料格式。tar會做成.tar壓縮檔。你也可以用plain,這樣會直接複製資料夾結構。-z— 壓縮備份,省空間。誰不想備份小一點?-P— 顯示即時進度。這樣你就知道有在跑,不會以為卡住了。
範例:
pg_basebackup -D /backups/university_backup -F tar -z -P
執行完後,/backups/university_backup 這個資料夾裡就會有一個 .tar 格式的備份檔。
用 pg_basebackup 的好處
效率:增量備份不用重複存沒變的資料,省時間又省空間。
簡單:pg_basebackup 會自動處理所有細節,連 WAL 檔都幫你搞定。
可靠:因為跟 PostgreSQL 機制整合,pg_basebackup 做出來的備份很精準,還原也很簡單。
實戰範例
來點實作吧。下面是一些用 pg_basebackup 做 PostgreSQL 備份的真實例子。會教你怎麼做基本備份、怎麼加壓縮、還有怎麼開啟 WAL 日誌歸檔,這樣就能做「時間點還原」。這些指令新手老手都用得到。
建立基本備份
pg_basebackup -D /backups/full_backup -F tar -z -P
結果:你會拿到一個 .tar 格式的完整資料庫備份。
設定壓縮跟格式
來做一個高壓縮的備份:
pg_basebackup -D /backups/full_backup -F tar -z -Z 9 -P
這裡 -Z 9 是壓縮等級(最高 9)。
WAL 歸檔
如果你有設定 WAL 歸檔,資料庫就能還原到任何時間點。這是設定 WAL 備份的指令:
pg_basebackup -D /backups/incremental_backup -F tar -z -P --wal-method=archive
GO TO FULL VERSION