行程模型#
PostgreSQL 伺服器實例由數個彼此互動的行程(process)組成。
伺服器啟動時第一個被拉起的行程是 postgres,傳統上稱為 postmaster。它負責:
- 衍生(spawn)所有其他行程(類 Unix 系統使用
fork系統呼叫) - 監督這些行程:任一行程失敗時重新啟動它;若共享資料有損毀風險,則重啟整個伺服器
側註:為什麼還沒改用執行緒?
行程模型因其簡單性,從一開始就被 PostgreSQL 採用,而關於是否改用執行緒(thread)的討論也從未停歇。
現行模型有幾項缺點:
- 靜態共享記憶體配置,導致緩衝快取之類的結構無法即時調整大小
- 平行演算法難以實作,效率也不如理想
- session 與行程緊密綁定
改用執行緒聽起來很有前景,儘管會牽涉隔離、作業系統相容性與資源管理等挑戰。然而其實作需要徹底翻修程式碼、投入數年時間,因此目前保守觀點佔上風:近期不會有這類改變。
背景行程#
伺服器的運作由背景行程(background process)維持,主要有:
| 行程 | 職責 |
|---|---|
startup | 故障後復原系統 |
autovacuum | 移除表格與索引中的過期資料 |
wal writer | 把 WAL 條目寫入磁碟 |
checkpointer | 執行檢查點(checkpoint) |
writer | 把髒頁(dirty page)刷回磁碟 |
stats collector | 蒐集實例的使用統計 |
wal sender | 把 WAL 條目送往備援節點(replica) |
wal receiver | 在備援節點接收 WAL 條目 |
其中有些行程在任務完成後即終止,有些一直在背景執行,還有一些可以關閉。
每個行程都由組態參數控制,有時多達數十個。要全面地調校伺服器,你必須理解它的內部運作。但一般性的考量只能幫你選出還算合適的初始值;之後這些設定仍須依監控資料進行微調。
共享記憶體與快取#
為了讓行程能互相溝通,postmaster 會配置共享記憶體(shared memory),供所有行程存取。
由於磁碟(尤其是 HDD,但 SSD 也一樣)比 RAM 慢得多,PostgreSQL 使用快取:把部分共享記憶體保留給最近讀取的頁面,期待它們會被多次需要,藉此降低重複存取磁碟的開銷。修改過的資料也不會立即寫回磁碟,而是延遲一段時間後才刷出。
- 緩衝快取(buffer cache)佔據共享記憶體的大部分
- 共享記憶體中還包含其他伺服器用來加速磁碟存取的緩衝區
作業系統也有自己的快取。PostgreSQL(幾乎)從不繞過作業系統機制去做 direct I/O,因此會產生雙重快取(double caching)。

圖 1-4:PostgreSQL 實例的行程與記憶體結構——postmaster、backend、背景行程、共享記憶體中的緩衝快取,以及作業系統快取
故障與 WAL#
發生故障時(例如斷電或作業系統當機),保存在 RAM 中的資料會全部遺失,緩衝快取也不例外。留在磁碟上的檔案,其頁面是在不同時間點寫入的——彼此並不一致。
為了能還原資料一致性,PostgreSQL 在運作期間會維護預寫式日誌(write-ahead log,WAL),讓遺失的操作在必要時能被重做。