PostgreSQL爲什麼要設置hot_standby_feedback

問題背景

Postgresql從9.1開始支持流複製,流複製的出現是一次革命,因爲它速度非常快,性能很好。流複製是基於wal日誌的複製技術,主庫不斷髮送wal日誌至備庫,備庫進行應用回放。
但是有時我們可能會在備庫進行某個查詢,然後遇到查詢中途突然拋出如下錯誤:

ERROR:canceling statement due to confilct with recovery。

遇到這個錯誤很不幸,因爲我們並不希望在備庫運行一個長查詢的最後時刻被告知查詢取消。那麼這個問題的原因是什麼?又應該怎樣預防呢?下面我們來探討一下。

從報錯我們可以看出,查詢取消的原因是因爲和恢復進程發生了衝突。那麼爲什麼會產生衝突呢?我們細想一下,比如說備庫正在執行基於某個表的查詢(這個查詢可能是應用產生的,也可能是手動連接進行的查詢),這時主庫執行了drop table操作,該操作寫入wal日誌後傳至備庫進行應用,爲了保證數據一致性,postgresql必然會迅速回放數據,這時drop table和select就會形成衝突。如下圖所示:
在這裏插入圖片描述

問題原因

這樣我們就知道了可能造成衝突的場景,總結一下有以下幾種情況:

①主庫由於產生請求排他鎖的操作傳遞至備庫產生的衝突,例如上圖所示,主庫執行drop table、truncate table、alter table等操作,在備庫進行回放時都有可能與備庫正在進行的查詢衝突。
②由於主庫vacuum清理掉無用元組造成的衝突,當某些由於頻繁更新或刪除的表中vacuum進程發現某個頁面中全部都是dead tuple(死亡元組)時,會嘗試請求排他鎖來進行清理,這樣的話可能會與備庫的查詢產生衝突。那麼普通vacuum會造成衝突嗎?答案是肯定的。比如備庫進行一個查詢沒有結束,如果主庫vacuum掉了備庫查詢所需要的元組時,就會產生衝突。

問題處理

其實還有一種情況會造成查詢衝突,說這種情況之前我們先來看看如何進行查詢衝突的預防。下面的圖片指明瞭查詢衝突產生的流程:
在這裏插入圖片描述

我們可以通過設置如下幾個參數進行查詢衝突的控制。

hot_standby_feedback:
這個參數是查詢衝突這個話題中提到最多的參數,下面我們詳細探討一下。我們假設在沒有備庫的情況下,會話1查詢某行數據,會話2刪除該數據,然後commit,此時會話2執行一次vacuum,我們知道這次vacuum並不會刪除該行數據,因爲會話1的事務還需要使用該元組,所以不會清理該元組。那麼如果是主從呢?主庫在準備進行vacuum時怎麼知道從庫還在進行查詢,這就是設置該參數的意義,設置hot_standby_feedback參數之後備庫會定期向主庫通知最小活躍事務id(xmin)值,這樣使得主庫vacuum進程不會清理大於xmin值的事務。

這個參數有利於減少衝突的發生,但並不能完全避免衝突,其實細想一下,這個參數只是減少了由於主庫vacuum死亡元組造成的衝突,並不能解決排他鎖造成的衝突。同時還有我們上面提到的第三種情況:由於網絡中斷造成的衝突,假如主備之間的網絡中斷後,備庫就無法向主庫正常發送xmin值,如果時間夠長,主庫在這段時間內還是會清理無用元組,這樣網絡恢復後就可能發生上面的vacuum造成的衝突。

這個參數的設置是有利有弊,好處就是減少了衝突,缺點就是由於主庫的清理需要等待備庫的事務結束,那麼在頻繁更新的場景下,可能造成主庫數據膨脹。所以我們在生產中設置hot_standby_feedback一般與下面幾個參數一起使用,能夠有效的降低衝突發生的概率。

值得注意的是hot_standby_feedback參數並不會覆蓋主庫上old_snapshot_threshold參數限定的值,old_snapshot_threshold參數限制了死亡元組的無限膨脹,當事務信息超過old_snapshot_threshold的限制時,依然會進行清理。

max_standby_streaming_delay:
備機因爲接收wal流日誌產生查詢衝突而取消查詢之前的等待時間,設置該參數會在發生衝突時,備庫查詢不會立即取消,而是等待一個時間後如果還沒結束再拋出報錯。這個值的大小可以參考備庫可能產生的長事務運行時間。

max_standby_archive_delay:
備機因爲處理歸檔的wal日誌產生查詢衝突而取消查詢之前的等待時間,和上面的參數類似。

vacuum_defer_cleanup_age:
指定vacuum延遲清理死亡元組的事務數,vacuum會延遲清除無效的記錄,延遲的事務個數通過vacuum_defer_cleanup_age進行設置。即vacuum和vacuum full操作不會立即清理剛剛被刪除元組。

生產環境裏我們可以根據pg_stat_database和pg_stat_database_confliects視圖查看衝突發生的情況,以此來進行如上參數的調整。

技術永無止境,加油吧。

歡迎關注我的公衆號:數據庫架構之美

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章