?
This document uses PHP Chinese website manual Release
有幾個與WAL相關(guān)的參數(shù)會影響數(shù)據(jù)庫性能。 本節(jié)討論它們的使用。參閱Chapter 18 獲取有關(guān)服務(wù)器配置參數(shù)的一般信息。
檢查點(diǎn)是事務(wù)序列中的點(diǎn), 在該點(diǎn)之前的所有信息都確保已經(jīng)寫到數(shù)據(jù)文件中去了。在檢查點(diǎn)時(shí), 所有臟數(shù)據(jù)頁都刷新到磁盤并且向日志文件中寫入一條特殊的檢查點(diǎn)記錄。 (改變以前刷新的WAL的縮寫文件。) 在發(fā)生崩潰的時(shí)候,崩潰恢復(fù)過程查找最后的檢查點(diǎn)記錄,判斷應(yīng)該從 日志中的哪個點(diǎn)(稱為redo記錄)開始REDO操作,在該記錄之前對數(shù)據(jù)文 件的任何修改都被認(rèn)為已經(jīng)寫在磁盤上了。因此,在檢查點(diǎn)完成之后, 任何在包含redo記錄點(diǎn)之前的日志段都不再需要,因此可以循環(huán)使用或者刪除。 當(dāng)然,在進(jìn)行WAL 歸檔的時(shí)候, 這些日志在循環(huán)利用或者刪除之前必須先歸檔。
按檢查點(diǎn)要求,刷新所有垃圾數(shù)據(jù)頁面到磁盤會導(dǎo)致顯著的I/O負(fù)載,因此, 檢查點(diǎn)進(jìn)行了限制,在下一個檢查點(diǎn)開始時(shí),I/O在檢查點(diǎn)開始結(jié)束時(shí)開啟。 這會在檢查點(diǎn)進(jìn)行時(shí)降低性能損耗。
服務(wù)器的后端寫進(jìn)程每checkpoint_segments個日志段或每 checkpoint_timeout秒就創(chuàng)建一個檢查點(diǎn),以先到為準(zhǔn)。 缺省設(shè)置分別是3個段和300秒(5分鐘)。我們也可以用SQL命令 CHECKPOINT強(qiáng)制創(chuàng)建一個檢查點(diǎn)。
減少checkpoint_segments和/或 checkpoint_timeout會更頻繁的創(chuàng)建檢查點(diǎn)。 這樣就允許更快的崩潰后恢復(fù)(因?yàn)樾枰刈龅墓ぷ鞲?。 不過,我們必須在更快的恢復(fù)與更頻繁的刷新臟數(shù)據(jù)頁所帶來的額外開銷之間進(jìn)行平衡。 并且,如果開啟了full_page_writes(缺省開啟), 那么還有其它的因素需要考慮。為了保證數(shù)據(jù)頁的一致性, 在每個檢查點(diǎn)之后的第一次數(shù)據(jù)頁變化會導(dǎo)致對整個頁面內(nèi)容的日志記錄。 因此,減小檢查點(diǎn)時(shí)間間隔會導(dǎo)致輸出到WAL日志中的數(shù)據(jù)量增加, 從而抵銷一部分縮短間隔的目標(biāo),并且無論如何都會產(chǎn)生更多的磁盤I/O操作。
檢查點(diǎn)的開銷相當(dāng)高,首先是因?yàn)樗枰獙懗鏊挟?dāng)前臟緩沖區(qū), 其次是因?yàn)閷?dǎo)致前面討論過的額外后繼WAL流量。因此把檢查點(diǎn)參數(shù)設(shè)置得足夠高, 讓檢查點(diǎn)發(fā)生的頻率降低是明智的。可以通過設(shè)置checkpoint_warning 對檢查點(diǎn)參數(shù)進(jìn)行一個簡單自檢。如果檢查點(diǎn)發(fā)生的間隔接近checkpoint_warning秒, 那么將向服務(wù)器日志輸出一條消息,建議你增加checkpoint_segments的數(shù)值。 偶爾出現(xiàn)這樣的警告并不會導(dǎo)致警報(bào),但是如果出現(xiàn)得太頻繁,那么就應(yīng)該增加檢查點(diǎn)控制參數(shù)。 如果你沒有把checkpoint_segments設(shè)置得足夠大, 那么批量操作的時(shí)候(比如大批的 COPY 傳輸)會導(dǎo)致出現(xiàn)大量此類警告消息。
為了避免大量的塊寫操作塞滿I/O系統(tǒng),在一段時(shí)間內(nèi),在檢查點(diǎn)期間寫臟緩沖。 這個時(shí)間是由checkpoint_completion_target控制的,作為檢查點(diǎn)時(shí)間間隔的一小部分。 調(diào)整I/O速率以便當(dāng)從檢查點(diǎn)開始時(shí)給出的checkpoint_segmentsWAL段的分?jǐn)?shù)已使用完, 或已經(jīng)過了給定的checkpoint_timeout秒數(shù)時(shí)停止檢查點(diǎn)。 缺省值是0.5,PostgreSQL可以在下次檢查點(diǎn)開始之前用大約一半的時(shí)間完成檢查點(diǎn)。 在一個正常操作時(shí)就很接近最大I/O吞吐量的操作系統(tǒng)上,可以增加checkpoint_completion_target以降低 檢查點(diǎn)時(shí)的I/O負(fù)載。這樣做的弊端在于會延長檢查點(diǎn),從而影響恢復(fù)時(shí)間,因?yàn)闀A舾嗟脑诨謴?fù)中可能用到的WAL段。 盡管checkpoint_completion_target最大可以設(shè)置為1.0,最好不要設(shè)置那么大,最大0.9,因?yàn)闄z查點(diǎn)期間的操作不僅僅 包括寫臟緩沖區(qū)。設(shè)置為1.0極有可能會導(dǎo)致不會按時(shí)完成檢查點(diǎn),從而由于所需的WAL段的數(shù)目的意外變化造成性能丟失。
至少會有一個 WAL 段文件,而且通常不會超過wal_keep_segments或 (2 + checkpoint_completion_target) * checkpoint_segments+1 個文件。 每個段文件通常為 16MB(你可以在編譯服務(wù)器的時(shí)候修改它)。 你可以用這些信息來估計(jì) WAL 需要的空間。 通常,如果一個舊日志段文件不再需要了,那么它將得到循環(huán)使用 (重命名為順序的下一個可用段)。如果由于短期的日志輸出高峰導(dǎo)致了超過 3 * checkpoint_segments+1 個段文件, 那么當(dāng)系統(tǒng)再次回到這個限制之內(nèi)的時(shí)候,多余的段文件將被刪除, 而不是循環(huán)使用。
在歸檔或待機(jī)模式時(shí),服務(wù)器在正常操作中會定期執(zhí)行類似于檢查點(diǎn)的 restartpoints: 服務(wù)器會強(qiáng)制將他的狀態(tài)寫入磁盤,更新pg_control文件來表明 預(yù)處理WAL數(shù)據(jù)不需要再次掃描,然后便會回收在pg_xlog目錄下所有舊日志文件。 一個重啟點(diǎn)的觸發(fā)在上一個重啟點(diǎn)至少一個檢查點(diǎn)記錄已經(jīng)重新運(yùn)行并且checkpoint_timeout通過時(shí)。 在標(biāo)準(zhǔn)模式下,如果一個checkpoint_segments日志聲明,重啟點(diǎn)的觸發(fā)同樣在上一個重啟點(diǎn) 至少一個檢查點(diǎn)記錄已經(jīng)重新運(yùn)行并且checkpoint_timeout通過時(shí)。 重啟點(diǎn)在主機(jī)不會比檢查點(diǎn)執(zhí)行的更多一些,因?yàn)橹貑Ⅻc(diǎn)僅能夠在檢查點(diǎn)記錄上執(zhí)行。
有兩個常用的內(nèi)部WAL函數(shù)LogInsert
和LogFlush
。
LogInsert
用于向共享內(nèi)存中的 WAL 緩沖區(qū)里添加一條新記錄。
如果沒有空間存放新記錄,那么 LogInsert
就不得不寫出(向內(nèi)核緩存里寫)
一些填滿了的 WAL 緩沖。我們可不想這樣,因?yàn)?LogInsert
用于每次數(shù)據(jù)庫低層修改(比如插入記錄)時(shí)都要在受影響的數(shù)據(jù)頁上持有一個排它鎖,因?yàn)樵摬僮餍枰娇煸胶茫? 更糟糕的是,寫 WAL 緩沖可能還會強(qiáng)制創(chuàng)建新的日志段,
它花的時(shí)間甚至更多。通常,WAL緩沖區(qū)應(yīng)該由一個LogFlush
請求來寫和刷新,在大部分時(shí)候它都是發(fā)生在事務(wù)提交的時(shí)候以確保事務(wù)記錄被刷新到永久存儲器上去了。
在那些日志輸入量比較大的系統(tǒng)上LogFlush
請求可能不夠頻繁,
這樣就不能避免 LogInsert
進(jìn)行寫操作。在這樣的系統(tǒng)上,
我們應(yīng)該提高配置參數(shù)wal_buffers的值(缺省為 8)來
增加WAL緩沖區(qū)的數(shù)量。增加這個數(shù)值將造成共享內(nèi)存使用量的增加。
如果設(shè)置了full_page_writes并且系統(tǒng)相當(dāng)繁忙,
把這個數(shù)值設(shè)置得高一些將有助于在緊隨每個檢查點(diǎn)之后的時(shí)間里平滑響應(yīng)時(shí)間。
commit_delay定義了后端在使用LogInsert
向日志中寫了一條已提交的記錄之后,再執(zhí)行一次LogFlush
之前休眠的毫秒數(shù)。這樣的延遲可以允許其它的后端把它們提交的記錄追加到日志中,
這樣就可以用一次日志同步把所有日志刷新到日志中。如果沒有打開fsync
或者當(dāng)前少于commit_siblings個處于活躍事務(wù)狀態(tài)的其它后端時(shí)則不會發(fā)生休眠;
這樣就避免了在其它事務(wù)不會很快提交的情況下睡眠。請注意,在大多數(shù)平臺上,
休眠要求的分辯率是 10 毫秒,所以任何介于 1 和 10000 微秒之間的非零commit_delay
的作用都是一樣的。適用這些參數(shù)的比較好的數(shù)值還不太清楚;我們鼓勵你多做試驗(yàn)。
wal_sync_method參數(shù)決定PostgreSQL 如何請求操作系統(tǒng)內(nèi)核強(qiáng)制將WAL更新輸出到磁盤。 只要滿足可靠性,那么所有選項(xiàng)應(yīng)該都是一樣的,除 fsync_writethrough,可有時(shí) 強(qiáng)制刷新磁盤高速緩存,即使其他選項(xiàng)時(shí),不這樣做。 然而,這是很具體的平臺,其中之一將是最快的; 在PostgreSQL源代碼樹,你可以測試選項(xiàng)的速度,使用的實(shí)用src/tools/fsync。 請注意如果你關(guān)閉了fsync的話這個參數(shù)就無關(guān)緊要了。
打開 wal_debug配置參數(shù)(前提是編譯
PostgreSQL 的時(shí)候打開了這個支持)
將導(dǎo)致每次LogInsert
和 LogFlush
WAL調(diào)用都被記錄到服務(wù)器日志。
這個選項(xiàng)以后可能會被更通用的機(jī)制取代。