標籤:
2.4 調整檢查點和XLOG
目前為止,這一章已經提供深入洞察PostgreSQL如何寫入資料,一般來說,XLOG是用來幹什麼的。考慮到這方面的知識,我們現在可以繼續並學習我們能做些什麼來使我們的資料庫在複製和單台伺服器啟動並執行兩種情況更加有效工作。
2.4.1 理解檢查點
在本章中,我們已經看到在資料可能到其它地方之前,它已經被寫入到了XLOG。問題是,如果XLOG從未被刪除,顯然,在沒有填滿磁碟的同一時間,我們不會永遠寫到XLOG中。
要解決這個問題,XLOG必須在某一時刻被刪除。這個過程就是所謂的檢查點。
從這個問題所帶來的主要問題是:什麼時候XLOG可以被截斷到某一特定的點?答案是:PostgreSQL把XLOG中所有的東西都放到隱藏檔中。如果XLOG中的所有更改也被放到資料檔案中,XLOG才可以被截斷。
[請記住,唯寫資料是沒有價值的,我們還必須把資料重新整理到資料表中。]
在某種程度上,XLOG可以被看作在有情況發生時,資料檔案修理工。如果一切都被完全修複,修理指令就可以被放心地刪除了。這就是在一個檢查點期間所發生的。
2.4.2 配置檢查點
對一致性來說,檢查點是非常好重要的,但是它們對效能來說也是非常重要的。如果檢查點配置不當,您可能會面臨嚴重的效能下降。
當談到配置檢查點,下面是一些相關參數。請注意,所有這些參數可以在postgresql.conf 中變更:
checkpoint_segments = 3
checkpoint_timeout = 5min
checkpoint_completion_target = 0.5
checkpoint_warning = 30s
在下面的章節中,我們將看看這些變數:
關於段和逾時
checkpoint_segments 和 checkpoint_timeout 將定義兩個檢查點之間的距離。檢查點發生或者當我們用完段或者實際到了。
請記住,一個段通常是16MB,所以三個段意味著我們將每48MB做一個檢查點。在現代硬體上,16MB是遠遠不夠的。在一個典型的生產系統中,一個檢查點256個間隔或者更高是完全可行的。
但是,當設定checkpoint_segments的時候,有一件事必須記在您的腦後:在崩潰的情況,PostgreSQL必須重放自從最後一個檢查點的所有的更改。如果兩個檢查點之間的距離非常大,您可能會注意到,您的故障資料庫執行個體需要很長的時間才能再次啟動。為了可用性,這種情況應該避免。
[在崩潰之後,總會有效能與恢復之間的權衡;您必須平衡您相應的配置。]
checkpoint_timeout 也非常重要。它是兩個檢查點之間所允許的時間上線。不更改時間而無限制地增加checkpoint_segments是沒有意義的。在大型系統中,對許多人來說,增加checkpoint_timeout已被證明是有意義的。
[在PostgreSQL中,您會發現,有一個交易記錄的常數。不同於在其它資料庫系統中,XLOG檔案的數目和事務的最大尺寸沒有關係;一個事務的大小可以很容易地超過兩個檢查點之間的距離。]
寫或不寫?
我們在本章已經知道,在COMMIT時,我們不能確定資料是否已經在資料檔案。
因此,如果資料檔案不必是一致的,為什麼不改變資料寫入的時間點?這正是我們使用checkpoint_completion_target可以做到的。這個思想是有一個指定檢查點完成的目標,作為兩個檢查點之間的總時間的一部分。
現在讓 我們討論三個情境來說明checkpoint_completion_target的目的:
情境1-儲存股市資料
在這個情境中,我們將儲存道瓊斯工業(DJIA)所有股票的最近行情。我們不想儲存所有股票價格的曆史,而是最近的,當前的價格。
考慮到我們正在處理的資料的類型,我們可以假設我們有一個由UPDATE語句決定的工作負載。
會發生什嗎?PostgreSQL必須一遍又一遍地更新相同的資料。鑒於一個事實,DJIA由30個不同的股票組成,資料量是非常有限的,並且我們的表也非常小。除此之外,價格可能每秒更新一次,或者更頻繁。
在內部,情況是這樣的:當第一個UPDATE到來時,PostgreSQL將獲得一個塊,放入記憶體並修改它。每一個後續的UPDATE將最有可能改變相同的塊。從邏輯上講,所有的寫操作必須寫到交易記錄,但是在共用緩衝區中的緩衝塊發生了什嗎?一般的規則是:如果有許多UPDATE(分別對相同的塊做更改),儘可能地把塊儲存在記憶體中是明智的;這將通過一個寫多個變化更改來極大地增加避免I/O的可能性。
[如果你要增加在一個磁碟I/O有許多更改的肯能性,考慮降低checkpoint_complection_target。塊將在記憶體中停留更長的時間,因此在寫發生之前,很多變化可能進入相同的塊。.]
該方案只是介紹,checkpoint_completion_target 為 0.05(或者5%)可能是合理的。
情境2-批量裝載
在我們的第二個情境中,我們將載入1TB的資料到一個空表。如果你正在一次載入這麼多的資料,再次命中你十分鐘之前命中的資料區塊的可能性是多少?這個可能性基本上是0,在這種情況下,緩衝區沒有一點寫入,因為我們會很容易通過空閑以及等待I/O的發生而錯過磁碟的容量。
在批量載入期間,我們要使用我們一直都有的所有的I/O能力。為了確保PostgreSQL立即把資料寫出來,我們必須把checkpoint_completion_target的值增加到接近1。
情境3-I/O峰值和輸送量方面的考慮
尖銳的劍鋒可以殺死你,至少它們可以造成應該避免的嚴重的傷害。在你周圍的真實世界中真實的東西在資料庫世界中也是真實。
在這個情境中,我們要假設一個應用程式儲存一個電話公司所謂的詳細通話記錄(CDRs)。你可以想象,很多寫將會發生,並且人們一整天都在打電話。當然,會有人們在打電話時,立即有另外一個電話跟在後面,但我們也將見證好多人在一周之內只打一次電話。
從技術上將,這意味著有一個好機會,在共用記憶體中的塊,它最近已經被更改了,將面臨第二次或者第三次的更改,但是,我們也將對那些不再被訪問的塊做出巨大的更改。
這種情況我們該如何處理呢?晚點寫出資料,以便儘可能多的更改將在之前已經修改過的頁面上變更。但是,在檢查點期間會發生什麼呢?如果更改(在這種情況下,髒頁)囤積了太長時間,檢查點本身將會很激烈,很多塊必須在很短的時間內被寫入。這會導致所謂的I/O劍鋒。在一個I/O劍鋒,你會看到你的系統是繁忙的。這可能顯示缺少回應時間,缺少回應時間可以被你的終端使用者感受到。
這給問題增加了一個維度:可預測的回應時間。
讓我們這樣說吧:讓我們假設你已經成功地使用了一段時間的網上銀行。你很高興。現在,一些人在你的網上銀行找到了一個調整方法,這使得網上銀行背後的資料庫快了50%,但是,這增加了一個缺點:每天有兩個小時,該系統不可達。顯然,從效能的角度來說,輸送量會比較好:
24 hours * 1 X < 22 hours * 1.5 X
但是,你的客戶會開心嗎?很顯然,你不會。這是一個典型的使用者案例,最佳化最大輸送量並沒有好處。如果你可以滿足你效能需求,有均勻的回應時間而有一點小小的效能損失作為代價可能是明智的。在我們的銀行的例子中,這將意味著你的系統是24×7運行而不是每天只運行22小時。
[如果你的互連網頻寬比以前快10倍,你會頻繁地支付你負擔嗎?顯然,你不會。有時,它不是關於每秒多少事務的最佳化,而是你以最合理的方式處理一個預先定義的負載量的最佳化方法。]
同樣的概念也適用於我們的電話應用程式。我們在檢查點期間寫所有的更改,因為這可能導致檢查點期間的延遲問題。這對立即更改資料檔案也沒有好處(意思是:高的checkpoint_completion_target),因為我們會寫得太多,太頻繁。
這是一個你必須妥協的典型的例子,checkpoint_completion_target為0.5 可能在這種情況下是最好的注意。
結論
從三個例子中得出的結論是,沒有適合所有用途的配置。為了得出一個好的可行的配置,你真的需要考慮一下你在處理的資料類型。對於許多應用,0.5的值已經證明剛剛好。
2.4.3 調整WAL緩衝區
在本章中,我們已經調整了一些重要的參數,例如,shared_buffers, fsync,等等。還有一個參數,但是,這可能會對效能產生重大的影響。參數 wal_buffers 被設計用來告訴PostgreSQL,用多少記憶體來記錄目前還沒有被寫入磁碟的XLOG。所以,如果有人在注入大事務時,在COMMIT之前,PostgreSQL將不會把任何變化較小的表寫到XLOG。請記住,在崩潰期間,如果一個未提交的事務丟失了,我們不需要在意它,因為COMMIT是在日常生活中唯一重要的事情。在COMMIT發生之前,這對使用較大的塊寫XLOG很有意義。這正是wal_buffers做的:除非在postgresql.conf中手動更改,它是一個自動調整的參數(用-1表示),在XLOG寫回磁碟之前,它使得PostgreSQL花費3%的shared_buffers,但不超過16MB來保持XLOG。
[在老版本的PostgreSQL中,這個參數是64KB。對現代的機器來說 這麼低的值是不合理的。如果你在運行一個老版本的PostgreSQL,可以考慮把wal_buffers增加到16MB。對合理大小的資料庫執行個體來說,這通常是一個合理的值。]
PostgreSQL Replication之第二章 理解PostgreSQL的交易記錄(4)