背景:
PostgreSQL在寫入頻繁的場景中,可能會產生大量的WAL日誌,而且WAL日誌量遠遠超過實際更新的數據量。我們可以把這種現象起個名字,叫做「WAL寫放大」,造成WAL寫放大的主要原因有2點。
在checkpoint之後第一次修改頁面,需要在WAL中輸出整個page,即全頁寫(full page writes)。全頁寫的目的是防止在意外宕機時出現的數據塊部分寫導致資料庫無法恢復。
更新記錄時如果新記錄位置(ctid)發生變更,索引記錄也要相應變更,這個變更也要記入WAL。更嚴重的是索引記錄的變更又有可能導致索引頁的全頁寫,進一步加劇了WAL寫放大。
過量的WAL輸出會對系統資源造成很大的消耗,因此需要進行適當的優化。
磁碟IO
WAL寫入是順序寫,通常情況下硬碟對付WAL的順序寫入是綽綽有餘的。所以一般可以忽略。
網絡IO
對區域網內的複製估計還不算問題,遠程複製就難說了。
磁碟空間
如果做WAL歸檔,需要的磁碟空間也是巨大的。
優化手段:
PostgreSQL在未經優化的情況下,20倍甚至更高的WAL寫放大是很常見的,適當的優化之後應該可以減少到3倍以下。引入SSL/SSH壓縮或歸檔壓縮等外部手段還可以進一步減少WAL的生成量。
如何判斷是否需要優化WAL?關於如何判斷是否需要優化WAL,可以通過分析WAL,然後檢查下面的條件,做一個粗略的判斷:
FPI比例高於70%
HOT_UPDATE比例低於70%
以上僅僅是粗略的經驗值,僅供參考。並且這個FPI比例可能不適用於低寫負載的系統,低寫負載的系統FPI比例一定非常高,但是,低寫負載系統由於寫操作少,因此FPI比例即使高一點也沒太大影響。
優化WAL的副作用前面用到了3種優化手段,如果設置不當,也會產生副作用,具體如下:
延長checkpoint時間間隔
導致crash恢復時間變長。crash恢復時需要回放的WAL日誌量一般小於max_wal_size的一半,WAL回放速度(wal_compression=on時)一般是50MB/s~150MB/s之間。可以根據可容忍的最大crash恢復時間(有備機時,切備機可能比等待crash恢復更快),估算出允許的max_wal_size的最大值。
調整fillfactor
過小的設置會浪費存儲空間,這個不難理解。另外,對於頻繁更新的表,即使把fillfactor設成100%,每個page裡還是要有一部分空間被dead tuple佔據,不會比設置一個合適的稍小的fillfactor更節省空間。
設置wal_compression=on
需要額外佔用CPU資源進行壓縮,但根據實測的結果影響不大。