天天看點

PostgreSQL實體"備庫"的哪些操作或配置,可能影響"主庫"的性能、垃圾回收、IO波動

postgresql , 實體複制 , 垃圾回收 , vacuum_defer_cleanup_age , hot_standby_feedback , max_standby_archive_delay , max_standby_streaming_delay

postgresql 實體備庫的哪些配置,或者哪些操作,可能影響到主庫呢?

首先,簡單介紹一下postgresql的實體備庫,實體備庫就是基于postgresql wal流式複制,實時恢複的備庫。實體備庫在實體層面與主庫完全一緻,每一個資料塊都一樣。實體備庫允許在實時恢複的同時,對外提供隻讀的功能。

問題來了,隻讀操作可能和恢複會發生沖突,比如使用者正在備庫讀某個資料塊的資料,與此同時,實時恢複程序讀取到wal的記錄,發現需要修改這個資料塊的資料。此時恢複就與隻讀發生了沖突。

為了避免沖突,資料庫有哪些手段呢?

1. 主庫配置

1.1 vacuum_defer_cleanup_age

設定主庫垃圾回收的延遲,例如配置為1000,表示垃圾版本将延遲1000個事務再被回收。

2. 備庫配置

2.1 hot_standby_feedback

如果設定為on,備庫在執行query時會通知主庫,哪些版本需要被保留。

2.2 max_standby_archive_delay, max_standby_streaming_delay

表示當備庫的query與恢複程序發生沖突時,恢複程序最長的等待時間,當恢複程序從被沖突堵塞開始等待時間超過以上設定時,會主動kill與之發生沖突的query,然後開始恢複,直到catch up,才允許query與恢複程序再次發生沖突。

以上配置,要麼會傷害主庫,要麼會傷害備庫。都是有一定代價的。

1. vacuum_defer_cleanup_age > 0

代價1,主庫膨脹,因為垃圾版本要延遲若幹個事務後才能被回收。

代價2,重複掃描垃圾版本,重複耗費垃圾回收程序的cpu資源。(n_dead_tup會一直處于超過垃圾回收門檻值的狀态,進而autovacuum 不斷喚醒worker進行回收動作)。

當主庫的 autovacuum_naptime=很小的值,同時autovacuum_vacuum_scale_factor=很小的值時,尤為明顯。

代價3,如果期間發生大量垃圾,垃圾版本可能會在事務到達并解禁後,爆炸性的被回收,産生大量的wal日志,進而造成wal的寫io尖刺。

2. hot_standby_feedback=on

如果備庫出現了long query,或者repeatable read的長事務,并且主庫對備庫還需要或正查詢的資料執行了更新并産生了垃圾時,主庫會保留這部分垃圾版本(與vacuum_defer_cleanup_age效果類似)。

代價,與vacuum_defer_cleanup_age > 0 一樣。

3. max_standby_archive_delay, max_standby_streaming_delay

代價,如果備庫的query與apply(恢複程序)沖突,那麼備庫的apply會出現延遲,也許從備庫讀到的是n秒以前的資料。

前面分析了,當主庫設定了vacuum_defer_cleanup_age > 0或者備庫設定了hot_standby_feedback=on同時有long query時,都可能造成主庫的3個問題。

這個問題很容易複現。

開啟主庫的自動垃圾回收,同時設定為很小的喚醒時間,以及很小的垃圾回收門檻值。

這樣設定是為了防止膨脹,但是也使得本文提到的問題更加的明顯。

1. 建立測試表

2. 插入1000萬測試資料

3. 在hot standby上開啟一個repeatable read事務,執行一筆query,查詢test的全表

4. 在主庫更新test全表

5. 查詢test表目前的統計資訊,有1000萬條dead tuple

6. 造成的影響,讀io巨大(掃描test表,試圖回收垃圾,但是回收未遂),以及autovacuum worker的cpu開銷很大。

autovacuum worker process 不停被喚醒,掃描垃圾資料,但是不能對其進行回收,是以n_dead_tup一直不會下降,循環往複,autovacuum worker不斷被喚醒。

1. 備庫設定參數hot_standby_feedback=off

reload

問題馬上解除,垃圾被回收掉了。

autovacuum worker不會再被喚醒,是以主庫的cpu馬上下降。

同時垃圾回收會帶來一次很大的wal寫io。造成尖刺。

2. max_standby_archive_delay, max_standby_streaming_delay起作用,備庫的事務在apply沖突逾時後,被強制kill

略,複現方法一樣。

為了盡量的避免實體備庫的query與apply的沖突,postgresql提供了幾種方法,但是這些方法要麼會傷害主庫,要麼會傷害備庫。都有一定代價。

1. 不建議設定 vacuum_defer_cleanup_age > 0

2. 如果備庫有long query,同時需要實時性,可以設定hot_standby_feedback=on,同時建議将主庫的autovacuum_naptime,autovacuum_vacuum_scale_factor設定為較大值(例如60秒,0.1),主庫的垃圾回收喚醒間隔會長一點,如果突然産生很多垃圾,可能會造成一定的膨脹。

3. 如果備庫有long query,并且沒有很高的實時性要求,建議設定設定hot_standby_feedback=off, 同時設定較大的max_standby_archive_delay, max_standby_streaming_delay。

<a href="https://www.postgresql.org/docs/9.6/static/runtime-config-replication.html">https://www.postgresql.org/docs/9.6/static/runtime-config-replication.html</a>