25.3. WAL 配置

有幾個與 WAL 相關的參數會影響數據庫性能。 本節討論它們的使用。參閱 Section 16.4 獲取配置參數的細節。

檢查點(Checkpoints) 是事務序列中的點, 我們保證在該點之前的所有日志信息都更新到數據文件中去了。 在檢查點時,所有髒數據頁都衝刷到磁盤並且向日志文件中寫入一條特殊的檢查點記錄。 結果是,在發生崩潰的時候,恢復器就知道應該從日志中的哪條記錄(稱做 redo 記錄)開始做 REDO 操作, 因為在該記錄前的對數據文件的任何修改都已經在磁盤上了。 在完成檢查點處理之後,任何在 redo 記錄之前寫的日志段都不再需要, 因此可以循環使用或者刪除。(到基于 WALBAR (備份和恢復)實現的時候, 這些日志在循環利用或者刪除之前將先歸檔。)

服務器每隔一段時間就派生一個特殊的進程以創建下一個檢查點。 每隔 checkpoint_segments 個日志段就創建一個檢查點, 或者每隔 checkpoint_timeout 秒創建一個。 以先到為準。缺省設置分別是 3 個段和 300 秒。 我們也可以用 SQL 命令 CHECKPOINT 強制一個檢查點。

減少 checkpoint_segments 和/或 checkpoint_timeout 會令檢查點更頻繁一些。 這樣就允許更快的崩潰後恢復(因為需要重做的工作更少)。不過, 我們必須在這個目地和更頻繁地衝刷髒數據頁所帶來的額外開銷之間取得平衡。 另外,為了保證數據頁的一致性,在每個檢查點之後的第一次數據頁的變化會導致對整個頁面內容的日志記錄。 因此,檢查點時間間隔短了會導致輸出到日志中的數據的增加,會抵銷一部分縮短間隔的目標, 並且怎麼著都會產生更多的磁盤 I/O。

至少會有一個 16MB 的段文件,而且通常不會超過 2 * checkpoint_segments + 1 個文件。你可以用這些信息來估計 WAL 需要的空間。 通常,如果一個舊的日志段文件不再需要了,那麼它將得到循環使用(重命名為順序的下一個可用段)。 如果由于短期的日志輸出峰值,導致了超過 2 * checkpoint_segments + 1 個段文件, 那麼到系統再次回到這個限制之內的時候,多于的段文件會被刪除,而不是循環使用。

有兩個常用的 WAL 函數: LogInsertLogFlushLogInsert 用于向共享內存中的 WAL 緩衝區裡加一條新的記錄。如果沒有空間存放新記錄, 那麼LogInsert 就不得不寫出(向內核緩存裡寫)一些填滿了的WAL緩衝。 我們可不想這樣,因為 LogInsert 用于每次數據庫低層修改(比如,記錄插入), 都要花在受影響的數據頁上持有一個排它鎖的時間,因為該操作需要越快越好;更糟糕的是, 寫 WAL 緩衝可能還會強制創建新的日志段, 它花的時間甚至更多。通常,WAL 緩衝區應該由一個 LogFlush 請求來寫和衝刷, 在大部分時候它都是發生在事務提交的時候以確保事務記錄被衝刷到永久存儲器上去了。在那些日志輸入量比較大的系統上, LogFlush 請求可能不夠頻繁,這樣就不能避免 WAL 緩衝區被 LogInsert 寫。在這樣的系統上,我們應該通過修改配置參數 wal_buffers 的值來增加 WAL 緩衝區的數量。缺省的 WAL 緩衝區數量是 8。 增加這個數值將有對應的共享內存使用量的增加。

檢查點是開銷相當昂貴的操作,因為它們用操作系統的 sync() 調用強制所有髒的內核緩衝刷新到硬盤上。 繁忙的服務器可能會很快就把檢查點段文件填滿, 導致額外的檢查點。如果這樣的強制檢查點發生的頻率比 checkpoint_warning 秒要頻繁,那麼將在服務器日志裡輸出一條信息,建議你增加 checkpoint_segments

commit_delay 定義了後端在使用 LogInsert 向日志中寫了一條已提交的記錄之後, 在執行一次 LogFlush 之前休眠的毫秒數。 這樣的延遲可以允許其它的後端把它們提交的記錄追加到日志中,這樣就可以用一次日志同步把所有日志衝刷到日志中。 如果沒有打開fsync或者當前少于 commit_siblings 個其它後端處于活躍事務狀態的時候則不會發生休眠; 這樣就避免了在其它事務一時半會不會提交的情況下睡眠。 請注意在大多數平台上,休眠要求的分辯率是十毫秒, 所以任何介于 1 和 10000 微秒之間的非零 commit_delay 的作用都是一樣的。 適用這些參數的比較好的數值還不太清楚;我們鼓勵你多做試驗。

wal_sync_method 參數決定PostgreSQL 如何請求內核強制將 WAL 更新輸出到磁盤。只要滿足可靠性,那麼所有選項應該都是一樣的,但是哪個最快則可能和平台密切相關。 請注意如果你關閉了 fsync,那麼這個參數就無所謂了。

wal_debug 參數設置為任何非零值都會導致每次 LogInsertLogFlush WAL 調用都被記錄到服務器日志。目前,這個非零值是多少沒有什麼區別。這個選項以後可能會被更通用的機制取代。