openGauss備庫wal-replay與query衝突

奔跑的数据库發表於2024-03-14

openGauss 備庫 wal replay 與 query 衝突

概述

openGauss 的物理流複製邏輯繼承了 PostgreSQL,當一條資料從主庫做變更到可以在備庫查詢到最新的值,在 PostgreSQL 備庫分為三個階段,分別是寫入備庫作業系統(remote_write),將快取中的資料刷入到磁碟(on == flush),從磁碟將資料庫回放(remote_apply);在 openGauss(自編譯 1116 版本)備庫中的三個階段分別是接收 wal(remote_receive),寫入(remote_write),回放(remote_apply)。

日常生產環境中,為了分擔主庫的訪問壓力,備庫(hot_standby=on)常常需要對外提供只讀服務,此時備庫既要接受並重放透過流協議傳過來的 wal 資料,同時也要對外提供只讀查詢服務,這兩個任務同時進行難免會產生衝突,有時我們會發現備庫的查詢直接被取消中斷,當資料庫叢集備庫中出現如下所示的報錯。

ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed

當日志中出現這個報錯,說明 wal apply 的操作與 query 衝突,查詢的 sql 被取消,按常規來說 wal 資料回放級別應該是最高的,要保證備庫第一時間獲取並重放最新資料,與主庫的資料保持一致,但是考慮到備庫可以提供對外只讀查詢服務,新增引數 max_standby_streaming_delay 來告訴備庫,如果發現與備庫當前查詢衝突,需要等待 max_standby_streaming_delay 的時長,如果超過這個時長,查詢還沒結束,就直接取消掉查詢操作,而這種衝突常常出現在主庫執行 vacuum 和 ddl 操作。

衝突原因

出現衝突報錯的原因可能是由以下幾種情況產生:

  1. max_standby_streaming_delay 引數值設定過低 PostgreSQL 的預設值是 30s,openGauss 的預設值是 3s,這個值需根據不同的業務應用去設定。
  2. 備庫 sql 執行時間過長由於資料量增加或資料傾斜、表或索引膨脹等因素導致 sql 執行變慢。
  3. 備機伺服器壓力過大,處理慢主庫開啟了 full_page_writes,wal 的資料量變大,備庫需要處理的資料增多,是備庫的負載增加。

最佳化建議

  1. 調整引數值

    1. 適當增加 max_standby_streaming_delay 引數值,根據使用場景自定義設定。
    2. 設定引數 hot_standby_feedback = on,告訴主庫執行 vacuum 操作時需要跳過哪些歷史資料(不建議使用,會造成主庫表膨脹)。
    3. 主節點設定 vacuum_defer_cleanup_age 引數,延遲清理 dead row(不建議使用,不好控制有效值)。
    4. 關閉 full_page_writes 引數,開啟 enable_double_write 和 enable_incremental_checkpoint 引數來替代,openGauss 特性。
  2. 最佳化 sql 可透過執行計劃查詢 sql 變慢,執行效率變差的原因,並修復。

  3. 提升硬體配置檢視伺服器硬體資源使用情況,並做適當最佳化及調整。

  4. 開啟併發 apply(opengauss 特有)開啟併發回放引數 recovery_max_workers(預設值是 1,最大值是 4),來快速恢復 wal 資料並重放,提升效率。

相關文章