有幾個與WAL相關的設定參數會影響資料庫效能。本節說明它們的用途。請參閱第 19 章以取得設定伺服器組態參數的一般資訊。
檢查點是在交易序列中的某些點,保證堆積和索引資料檔案已使用在該檢查點之前寫入的所有資訊進行更新。在檢查點時間,所有髒資料頁面都會被刷新到磁碟,並且一個特殊的檢查點記錄會被寫入 WAL 檔案。(變更記錄先前已刷新到WAL檔案。)如果發生崩潰,崩潰恢復程序會查看最新的檢查點記錄,以確定 WAL 中的哪個點(稱為重做記錄)應該從哪個點開始 REDO 操作。在該點之前對資料檔案所做的任何變更保證已在磁碟上。因此,在檢查點之後,包含重做記錄之前的 WAL 區段不再需要,可以回收或移除。(當WAL正在進行歸檔時,WAL 區段必須在回收或移除之前進行歸檔。)
將所有髒資料頁面刷新到磁碟的檢查點需求可能會導致顯著的 I/O 負載。因此,檢查點活動會受到限制,以便 I/O 在檢查點開始時開始,並在下一個檢查點到期開始之前完成;這可以最大限度地減少檢查點期間的效能下降。
伺服器的檢查點程序會定期自動執行檢查點。每隔 checkpoint_timeout 秒開始一個檢查點,或者如果 max_wal_size 即將超過,以先到者為準。預設設定分別為 5 分鐘和 1 GB。如果自上次檢查點以來沒有寫入 WAL,即使 checkpoint_timeout
已經過,也會跳過新的檢查點。(如果正在使用 WAL 歸檔,並且您想要對檔案歸檔的頻率設定一個下限,以便限制潛在的資料遺失,您應該調整 archive_timeout 參數,而不是檢查點參數。)也可以使用 SQL 命令 CHECKPOINT
強制執行檢查點。
減少 checkpoint_timeout
和/或 max_wal_size
會導致更頻繁地發生檢查點。這允許更快的崩潰後恢復,因為需要重做的資料更少。但是,必須權衡這種優勢與更頻繁刷新髒資料頁面的成本。如果 full_page_writes 已設定(預設情況下如此),則還有另一個因素需要考慮。為了確保資料頁面一致性,每次檢查點後第一次修改資料頁面會導致記錄整個頁面內容。在這種情況下,較小的檢查點間隔會增加 WAL 的輸出量,部分抵消了使用較小間隔的目標,並且在任何情況下都會導致更多的磁碟 I/O。
檢查點的代價相當高,首先是因為它們需要寫出所有當前髒緩衝區,其次是因為它們會導致額外的後續 WAL 流量,如上所述。因此,明智的做法是將檢查點參數設定得足夠高,以使檢查點不會太頻繁地發生。作為對檢查點參數的簡單健全性檢查,您可以設定 checkpoint_warning 參數。如果檢查點發生的間隔比 checkpoint_warning
秒更短,則會將訊息輸出到伺服器日誌,建議增加 max_wal_size
。偶爾出現此類訊息並不需要驚慌,但如果它經常出現,則應增加檢查點控制參數。如果您沒有將 max_wal_size
設定得足夠高,大量操作(例如大型 COPY
傳輸)可能會導致出現許多此類警告。
為了避免大量的頁面寫入淹沒 I/O 系統,檢查點期間的髒緩衝區寫入會分散在一段時間內。此段時間由 checkpoint_completion_target 控制,該參數以檢查點間隔的分數表示(由 checkpoint_timeout
配置)。I/O 速率會進行調整,以便在經過 checkpoint_timeout
秒數的給定分數後,或在超過 max_wal_size
之前(以較早者為準)完成檢查點。預設值為 0.9,PostgreSQL 預期會在下一個排定的檢查點之前(約為上次檢查點持續時間的 90%)完成每個檢查點。這會盡可能分散 I/O,使檢查點 I/O 負載在整個檢查點間隔內保持一致。這樣做的缺點是延長檢查點會影響恢復時間,因為需要保留更多的 WAL 區段以供恢復時使用。如果使用者擔心恢復所需的時間,可能會希望減少 checkpoint_timeout
,以便更頻繁地發生檢查點,但仍然將 I/O 分散在整個檢查點間隔內。或者,可以減少 checkpoint_completion_target
,但這會導致 I/O 更加密集的時間段(在檢查點期間)和 I/O 較少的時間段(在檢查點完成之後但在下一個排定的檢查點之前),因此不建議這樣做。雖然 checkpoint_completion_target
可以設定為高達 1.0,但通常建議將其設定為不超過 0.9(預設值),因為檢查點包含一些除了寫入髒緩衝區之外的其他活動。設定為 1.0 很可能導致檢查點無法按時完成,這會因所需 WAL 區段數量的意外變化而導致效能損失。
在 Linux 和 POSIX 平台上,checkpoint_flush_after 允許您強制檢查點寫入的 OS 頁面在達到可配置的位元組數後刷新到磁碟。否則,這些頁面可能會保留在 OS 的頁面快取中,從而在檢查點結束時發出 fsync
時導致停頓。此設定通常有助於減少交易延遲,但也會對效能產生不利影響;特別是對於大於 shared_buffers 但小於 OS 頁面快取的工作負載。
pg_wal
目錄中的 WAL 區段檔案數量取決於 min_wal_size
、max_wal_size
以及前幾個檢查點週期中產生的 WAL 數量。當不再需要舊的 WAL 區段檔案時,它們會被移除或回收(也就是重新命名為編號序列中的未來區段)。如果由於 WAL 輸出速率的短期高峰而超過了 max_wal_size
,則會移除不需要的區段檔案,直到系統恢復到此限制以下。低於該限制時,系統會回收足夠的 WAL 檔案,以涵蓋直到下一個檢查點的估計需求,並移除其餘的檔案。該估計基於先前檢查點週期中使用的 WAL 檔案數量的移動平均值。如果實際使用量超過估計值,則會立即增加移動平均值,因此它在一定程度上適應高峰使用量而不是平均使用量。min_wal_size
對於為將來使用而回收的 WAL 檔案數量設定了最小值;始終會為將來使用而回收這麼多的 WAL,即使系統處於閒置狀態且 WAL 使用量估計表明只需要少量 WAL 也是如此。
獨立於 max_wal_size
,始終會保留最近的 wal_keep_size 百萬位元組的 WAL 檔案以及一個額外的 WAL 檔案。此外,如果使用了 WAL 歸檔,則在歸檔之前無法移除或回收舊的區段。如果 WAL 歸檔無法跟上 WAL 的產生速度,或者如果 archive_command
或 archive_library
反覆失敗,則舊的 WAL 檔案會累積在 pg_wal
中,直到情況解決。使用複製槽的慢速或失敗的備用伺服器也會產生相同的效果(請參閱第 26.2.6 節)。
在歸檔恢復或備用模式下,伺服器會定期執行重新啟動點,這與正常操作中的檢查點類似:伺服器會強制將其所有狀態寫入磁碟,更新 pg_control
檔案以指示不需要再次掃描已處理的 WAL 資料,然後回收 pg_wal
目錄中的任何舊 WAL 區段檔案。重新啟動點的執行頻率不能高於主伺服器上的檢查點,因為重新啟動點只能在檢查點記錄處執行。重新啟動點可以根據排程或外部請求觸發。 pg_stat_checkpointer
檢視中的 restartpoints_timed
計數器會計數第一個,而 restartpoints_req
則計數第二個。如果在到達檢查點記錄時,自上次執行的重新啟動點以來至少經過了 checkpoint_timeout 秒,或者執行重新啟動點的先前嘗試失敗,則會根據排程觸發重新啟動點。在最後一種情況下,下一個重新啟動點將在 15 秒後排定。由於與檢查點類似的原因,主要是因為 WAL 大小即將超過 max_wal_size,因此會根據請求觸發重新啟動點。但是,由於何時可以執行重新啟動點的限制,在恢復期間,max_wal_size
通常會被超過,最多可達一個檢查點週期的 WAL。(max_wal_size
永遠不是硬性限制,因此您應該始終留出足夠的空間,以避免耗盡磁碟空間。) pg_stat_checkpointer
檢視中的 restartpoints_done
計數器會計數實際執行的重新啟動點。
在某些情況下,當主節點上的 WAL 大小快速增加時,例如在大量 INSERT 操作期間,備用節點上的 restartpoints_req
計數器可能會顯示出峰值增長。這是因為由於 XLOG 消耗量增加而請求建立新的重新啟動點無法執行,因為自上次重新啟動點以來的安全檢查點記錄尚未在備用節點上重播。此行為是正常的,不會導致系統資源消耗增加。只有重新啟動點相關計數器中的 restartpoints_done
計數器表示已消耗了明顯的系統資源。
有兩個常用的內部WAL函式:XLogInsertRecord
和 XLogFlush
。XLogInsertRecord
用於將新紀錄放入WAL共享記憶體中的緩衝區。如果沒有空間放置新紀錄,XLogInsertRecord
將必須寫入(移動到核心快取)幾個已滿的WAL緩衝區。這是不可取的,因為 XLogInsertRecord
用於每次資料庫底層修改(例如,行插入),並且此時會持有受影響資料頁面的獨佔鎖定,因此操作需要盡可能快。更糟糕的是,寫入WAL緩衝區也可能強制建立新的 WAL 段,這需要更多時間。通常,WAL緩衝區應由 XLogFlush
請求寫入和刷新,該請求主要在交易提交時發出,以確保交易記錄被刷新到永久儲存裝置。在高 WAL 輸出的系統上,XLogFlush
請求可能不會經常發生,以防止 XLogInsertRecord
必須執行寫入操作。在這種系統上,應通過修改 wal_buffers 參數來增加WAL緩衝區的數量。當 full_page_writes 被設定並且系統非常繁忙時,將 wal_buffers
設定得更高將有助於平滑在每次檢查點之後的時間段內的響應時間。
commit_delay 參數定義了在 XLogFlush
中取得鎖定後,群組提交領導者程序將休眠多少微秒,而群組提交追隨者則在領導者後面排隊。此延遲允許其他伺服器進程將其提交記錄添加到 WAL 緩衝區,以便所有這些記錄都將由領導者的最終同步操作刷新。如果未啟用 fsync,或者目前在活動交易中的其他會話少於 commit_siblings,則不會發生休眠;這避免了在不太可能有任何其他會話很快提交時休眠。請注意,在某些平台上,休眠請求的解析度為十毫秒,因此 1 到 10000 微秒之間的任何非零 commit_delay
設定都具有相同的效果。另請注意,在某些平台上,休眠操作可能比參數請求的時間稍長。
由於 commit_delay
的目的是允許每次刷新操作的成本在併發提交交易中分攤(可能以交易延遲為代價),因此有必要在智慧地選擇設定之前量化該成本。成本越高,commit_delay
在提高交易吞吐量方面的效果預計就越好,直到達到某個點。 pg_test_fsync 程式可用於測量單個 WAL 刷新操作所需的平均時間(以微秒為單位)。在單個 8kB 寫入操作後,程式報告的刷新平均時間的一半通常是 commit_delay
的最有效設定,因此建議將此值作為在針對特定工作負載進行最佳化時使用的起點。雖然在 WAL 儲存在高延遲旋轉磁碟上時,調整 commit_delay
特別有用,但即使在具有非常快速同步時間的儲存媒體(例如固態硬碟或具有電池備份寫入快取的 RAID 陣列)上,益處也可能非常顯著;但這絕對應該針對代表性的工作負載進行測試。在這種情況下,應使用更高的 commit_siblings
值,而較小的 commit_siblings
值通常在較高延遲的媒體上有幫助。請注意,commit_delay
的設定過高可能會導致交易延遲增加,以至於總交易吞吐量下降。
當 commit_delay
設定為零(預設值)時,仍然可能發生某種形式的群組提交,但每個群組僅由在上次刷新操作(如果有的話)發生期間達到需要刷新其提交記錄的點的會話組成。在較高的客戶端計數下,往往會發生 “幫派效應”,因此即使 commit_delay
為零,群組提交的效果也會變得顯著,因此顯式設定 commit_delay
的幫助往往較小。commit_delay
只有在 (1) 存在一些併發提交的交易,並且 (2) 吞吐量在一定程度上受到提交速率的限制時才能提供幫助;但在高旋轉延遲的情況下,即使只有兩個客戶端(即一個具有一個同級交易的提交客戶端),此設定也可以有效地提高交易吞吐量。
wal_sync_method 參數確定 PostgreSQL 如何要求核心強制WAL將更新寫出到磁碟。除了 fsync_writethrough
之外,所有選項在可靠性方面應該是相同的,fsync_writethrough
有時甚至可以在其他選項不執行此操作時強制刷新磁碟快取。但是,哪個選項最快取決於平台。您可以使用 pg_test_fsync 程式測試不同選項的速度。請注意,如果已關閉 fsync
,則此參數無關緊要。
啟用 wal_debug 配置參數(前提是 PostgreSQL 已編譯並支援它)將導致每個 XLogInsertRecord
和 XLogFlush
WAL呼叫被記錄到伺服器日誌中。此選項將來可能會被更通用的機制取代。
有兩個內部函式可用於將 WAL 資料寫入磁碟:XLogWrite
和 issue_xlog_fsync
。 當啟用track_wal_io_timing時,XLogWrite
寫入和 issue_xlog_fsync
同步 WAL 資料到磁碟的總時間量會分別計算為 pg_stat_wal 中的 wal_write_time
和 wal_sync_time
。XLogWrite
通常由 XLogInsertRecord
(當 WAL 緩衝區中沒有新紀錄的空間時)、XLogFlush
和 WAL 寫入器呼叫,以將 WAL 緩衝區寫入磁碟並呼叫 issue_xlog_fsync
。issue_xlog_fsync
通常由 XLogWrite
呼叫,以將 WAL 檔案同步到磁碟。 如果 wal_sync_method
是 open_datasync
或 open_sync
,則 XLogWrite
中的寫入操作保證將寫入的 WAL 資料同步到磁碟,而 issue_xlog_fsync
不執行任何操作。 如果 wal_sync_method
是 fdatasync
、fsync
或 fsync_writethrough
,則寫入操作會將 WAL 緩衝區移動到核心快取,並且 issue_xlog_fsync
會將它們同步到磁碟。 無論 track_wal_io_timing
的設定如何,XLogWrite
寫入和 issue_xlog_fsync
同步 WAL 資料到磁碟的次數也會分別計算為 pg_stat_wal
中的 wal_write
和 wal_sync
。
可以使用 recovery_prefetch 參數來減少恢復期間的 I/O 等待時間,方法是指示核心啟動對即將需要但目前不在 PostgreSQL 緩衝池中的磁碟區塊的讀取。maintenance_io_concurrency 和 wal_decode_buffer_size 設定分別限制預取並行性和距離。 預設情況下,它設定為 try
,這會在提供 posix_fadvise
的系統上啟用此功能。
如果您在文件中發現任何不正確、與您特定功能的體驗不符或需要進一步澄清之處,請使用此表單報告文件問題。