有幾個WAL-相關的配置引數會影響資料庫的效能。本節將解釋它們的使用方法。有關設定伺服器配置引數的一般資訊,請參閱第 19 章。
檢查點 是事務序列中的一些點,在這些點上,保證堆和索引資料檔案已更新為在檢查點之前寫入的所有資訊。在檢查點時,所有髒資料頁都會被重新整理到磁碟,並在 WAL 檔案中寫入一個特殊的檢查點記錄。(更改記錄以前被重新整理到WAL檔案。)如果發生崩潰,崩潰恢復過程會檢視最新的檢查點記錄,以確定 WAL (稱為重做記錄) 中應從何處開始執行 REDO 操作。在重做記錄之前的任何對資料檔案的更改都保證已在磁碟上。因此,在檢查點之後,包含重做記錄的 WAL 段之前的所有 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 節)。同樣,如果啟用了WAL 摘要,舊段將在摘要之前保留。
在歸檔恢復或備用模式下,伺服器會定期執行重啟點,這與正常操作中的檢查點類似:伺服器將所有狀態強制寫入磁碟,更新 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
計數器可能會顯示峰值增長。這是因為由於 WAL 消耗增加而建立新重啟點的請求無法執行,因為自上次重啟點以來安全檢查點記錄尚未在備用伺服器上重放。此行為是正常的,不會導致系統資源消耗增加。在重啟點相關的計數器中,只有 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 個其他會話當前處於活動事務中,則不會發生休眠;這可以避免在不太可能立即有其他會話提交時休眠。請注意,在某些平臺上,休眠請求的解析度為十毫秒,因此任何非零的 commit_delay
設定(介於 1 到 10000 微秒之間)都會產生相同的效果。另請注意,在某些平臺上,休眠操作可能比引數請求的時間稍長。
由於 commit_delay
的目的是允許每次重新整理操作的成本分攤到併發提交的事務上(可能以犧牲事務延遲為代價),因此有必要在合理地選擇設定之前量化該成本。該成本越高,commit_delay
在提高事務吞吐量方面預期會更有效,但也有一個上限。可以使用 pg_test_fsync 程式來測量單次 WAL 重新整理操作平均需要多少微秒。通常,報告的程式在一小時 8kB 寫操作後重新整理的平均時間的一半的延遲值是 commit_delay
的最有效設定,因此建議以此值作為最佳化特定工作負載的起點。雖然對 commit_delay
進行調優在 WAL 儲存在高延遲旋轉磁碟上時特別有用,但即使在同步時間非常快的儲存介質(如固態驅動器或帶有電池備份寫快取的 RAID 陣列)上,其優點也可能非常顯著;但這絕對應該根據代表性的工作負載進行測試。在這種情況下,應該使用更高的 commit_siblings
值,而在高延遲介質上,較小的 commit_siblings
值通常很有用。請注意,commit_delay
設定過高很有可能導致事務延遲過大,從而導致總事務吞吐量下降。
當 commit_delay
設定為零(預設值)時,仍然可能發生一種形式的組提交,但每個組將僅包含在先前重新整理操作(如果存在)正在發生的視窗期間達到需要重新整理其提交記錄的會話。在更高的客戶端數量下,會傾向於出現一種“通道效應”(gangway effect),因此即使 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 資料到磁碟的總時間分別作為 write_time
和 fsync_time
在 pg_stat_io 中為 object
wal
計數。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 資料到磁碟的次數也分別作為 writes
和 fsyncs
在 pg_stat_io
中為 object
wal
計數。
recovery_prefetch
引數可以用於透過指示核心啟動對即將需要但當前不在 PostgreSQL 緩衝區池中的磁碟塊的讀取,來減少恢復期間的 I/O 等待時間。maintenance_io_concurrency 和 wal_decode_buffer_size 設定分別限制了預讀併發度和距離。預設情況下,它設定為 try
,這會在支援發出預讀建議的系統上啟用該功能。
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表單 來報告文件問題。