查詢 RDS for PostgreSQL 資料庫執行個體的僅供讀取複本時,如何對錯誤 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)” 進行疑難排解?

上次更新日期:2022 年 6 月 23 日

我已設定 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 執行個體的僅供讀取複本。查詢僅供讀取副本時,出現錯誤 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)”。

簡短描述

由於主要執行個體對僅供讀取複本上發生的活動缺乏可見性,可能會發生此錯誤。當 WAL 資訊無法套用至僅供讀取複本時,會發生與復原的衝突,因為該變更可能會妨礙僅供讀取複本上發生的活動。

例如,假設當長時間執行的 SELECT 陳述式在主要執行個體上捨棄之表格上的僅供讀取複本上執行時,您在主要執行個體上執行 DROP 陳述式。則,僅供讀取複本有兩個選項:

  • 在套用 WAL 記錄之前,請等待 SELECT 陳述式的完成。於此狀況下,複寫延遲會增加。
  • 套用 WAL 記錄,然後取消 SELECT 陳述式。於此狀況下,你會遇到錯誤 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)"。

僅供讀取複本會依據 max_standby_streaming_delaymax_standby_archive_delay 來解決這些複寫衝突。max_standby_streaming_delay 參數可決定在取消與即將套用之 WAL 項目衝突的待命查詢之前,僅供讀取複本必須等待的時間。若衝突的陳述式仍持續持行於此這段期間之後,則 PostgreSQL 會取消陳述式並發出下列錯誤訊息:

ERROR: canceling statement due to conflict with recovery

您會遇到這個錯誤通常是因為在僅供讀取複本上長時間執行查詢。

於上述具有 DROP 陳述式的範例中,DROP 要求會存放於 WAL 檔案中,以於稍後套用在僅供讀取複本上,確保一致性。假設僅供讀取複本上已執行 SELECT 陳述式,該陳述式會嘗試從捨棄的物件擷取資料,其執行時間大於 max_standby_streaming_delay 中的值。則會取消 SELECT 陳述式,以套用 DROP 陳述式。

工作階段 1 (僅供讀取複本) 在 example_table 上執行 SELECT 陳述式

postgres=> SELECT * from example_table;

工作階段 2 (主要) 在 example_table 上執行 DROP 陳述式:

postgres=> DROP TABLE example_table;

則會出現下列錯誤:

postgres@postgres:[27544]:ERROR:  canceling statement due to conflict with recovery
postgres@postgres:[27544]:DETAIL:  User was holding a relation lock for too long.
postgres@postgres:[27544]:STATEMENT:  select * from example_table;

此外,當僅供讀取複本上的交易讀取主要執行個體上設定要刪除的元組時,可能會發生查詢衝突。刪除元組,然後在主要執行個體上進行清理,會造成與仍執行於複本上的 SELECT 查詢衝突。於此狀況下,複本上的 SELECT 查詢會遭到終止並顯示下列錯誤訊息:

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

解決方案

當僅供讀取複本遇到衝突,且在錯誤日誌出現錯誤 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)" 時,您可依據錯誤訊息設定某些自訂參數,以降低衝突的影響。請注意,必須在僅供讀取複本上設定自訂參數。

您會看到 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)" 錯誤,以及 "DETAIL: User was holding a relation lock for too long (詳細資訊:使用者持有關係所的時間過長)"

max_standby_streaming_delay/max_standby_archive_delay:您可使用這些參數,在取消與即將套用之 WAL 項目衝突的待命陳述式之前預留更多時間。這些值代表從主要執行個體接收資料後所允許套用 WAL 資料的總時間量。這些參數是依讀取 WAL 資料的位置來進行指定。若從串流複寫讀取 WAL 資料,則使用 max_standby_streaming_delay 參數。若從 Amazon Simple Storage Service (Amazon S3) 的封存位置讀取 WAL 資料,則請使用 max_standby_archive_delay 參數。

設定這些參數時,請注意下列事項:

  • 若將這些參數值設定為 -1,則允許複本執行個體永久等待完成衝突的查詢,進而增加複寫延遲。
  • 若您將這些參數值設定為 0,則會取消衝突的查詢,並在複本執行個體上套用 WAL 項目。
  • 這些參數的預設值會設定為 30 秒。
  • 若您在設定這些參數時並未指定單位,則會將毫秒視為單位。

依據您的使用案例,調整這些參數的值,以平衡查詢取消或複寫延遲。

注意:若您正在增加 max_standby_archive_delay 以避免取消與讀取 WAL 封存項目衝突的查詢,則請考慮增加 max_standby_stream 以避免與串流 WAL 項目衝突相關的取消。

您會看到 "canceling statement due to conflict with recovery (因與復原衝突而取消陳述式)" 錯誤,以及 "DETAIL: User query might have needed to see row versions that must be removed (詳細資訊:使用者查詢可能需要查看必須移除的列版本)"

hot_standby_feedback:若您啟動此參數,則意見回饋訊息會從僅供讀取複本傳送至主要執行個體,其中包含最早的作用中交易資訊。因此,主要執行個體不會移除交易可能需要的記錄。

當您在僅供讀取複本上啟動此參數時,僅供讀取複本上長時間執行的查詢可能會導致主要執行個體上的資料表膨脹。這是因為真空作業不會移除執行於僅供讀取複本上之查詢可能需要的無效元組。依預設關閉此參數。因此,啟動此參數時請務必小心。

您還可以檢查僅供讀取複本上的 pg_stat_database_conflicts 檢視,以取得因與僅供讀取複本上的復原衝突而取消之陳述式的統計資料。


此文章是否有幫助?


您是否需要帳單或技術支援?