PostgreSQLエラー:リカバリとの競合によりステートメントをキャンセルしています


139

スタンバイモードでPostgreSQL dbに対してクエリを実行すると、次のエラーが発生します。エラーの原因となるクエリは1か月間は正常に機能しますが、1か月以上クエリを実行するとエラーが発生します。

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

解決方法に関する提案はありますか?ありがとう


このエラーについて言及しているAWSのドキュメントを見つけてください。これにはソリューションaws.amazon.com/blogs/database/…
arunjos007

回答:


89

ホットスタンバイサーバーでクエリを実行するのはやや注意が必要です。クエリ中に必要な行がプライマリで更新または削除される可能性があるため、失敗する可能性があります。プライマリはクエリがセカンダリで開始されることを知らないため、古いバージョンの行をクリーンアップ(バキューム)できると考えています。次に、セカンダリはこのクリーンアップを再生し、これらの行を使用できるすべてのクエリを強制的にキャンセルする必要があります。

長いクエリはより頻繁にキャンセルされます。

これを回避するには、プライマリで繰り返し可能な読み取りトランザクションを開始します。これは、ダミークエリを実行し、実際のクエリがセカンダリで実行されている間はアイドル状態になります。その存在により、プライマリで古い行バージョンのバキューム処理が防止されます。

この問題とその他の回避策の詳細については、ドキュメントの「ホットスタンバイ-クエリの競合の処理」セクションで説明しています。


10
PostgreSQL 9.1以降のユーザーへ:実用的な解決策については、以下のeradmanの回答を参照してください。
ゾルタン2014

3
PostgreSQL 9.1以降のユーザーにとって:max-malyshの答えはより正直です。リスクを理解しない限り、エラーマンの提案を行わないでください。
ダボス

91

触れる必要はありませんhot_standby_feedback。他の人が述べたように、それをonマスターを膨らませるスレーブでトランザクションを開いて閉じないことを想像してください。

代わりに、を適切な値に設定max_standby_archive_delaymax_standby_streaming_delayます。

# /etc/postgresql/10/main/postgresql.conf on a slave
max_standby_archive_delay = 900s
max_standby_streaming_delay = 900s

このようにして、900秒未満の期間のスレーブに対するクエリはキャンセルされません。ワークロードに長いクエリが必要な場合は、これらのオプションをより高い値に設定してください。


1
これが私たちが最終的に使用したソリューションです。ここに提示されたすべてのオプション間の最良の妥協のようです。
mohit6up 2018年

2
これが最良の答えです。ドキュメントに従って、これらは累積的であることに注意してください。レプリケーションを保持しているレプリカに複数のクエリがある場合、899に到達すると、別の2秒のクエリがキャンセルされます。コードに指数バックオフを実装するのが最善です。また、レプリケーションのストリーミング中はストリーミング遅延が発生します。レプリケーションがストリーミングに対応できない場合は、アーカイブからレプリケーションに移行します。アーカイブから複製している場合は、おそらくそれを追いつくmax_standby_archive_delay必要があり、他よりも小さくする必要があるかもしれません。
ダボス

2
これはまだここでの最良の解決策です。Redshiftでは、パラメーターグループ設定を介してこれを設定できますが、それはにある必要があることにのみ注意してくださいms。つまり、900s = 16分= 900000msです。
NullDev

これをGCPで更新するには、ms cloud.google.com
sql /

スタンバイの目的がレポートなどであり、フェイルオーバーを処理する準備が必要なホットスタンバイではない場合、これが絶対に最善の答えです。
soupdog

77

マスターでアイドルトランザクションを開始する必要はありません。postgresql-9.1では、この問題を解決する最も直接的な方法は、

hot_standby_feedback = on

これにより、マスターは実行時間の長いクエリを認識できます。ドキュメントから:

最初のオプションは、パラメーターhot_standby_feedbackを設定することです。これにより、VACUUMが最近死んだ行を削除することがなくなり、クリーンアップの競合が発生しなくなります。

なぜこれがデフォルトではないのですか?このパラメーターは初期実装後に追加されたものであり、スタンバイがマスターに影響を与えることができる唯一の方法です。


11
このパラメータはスタンバイで設定する必要があります。
Steve Kehlet、2014

3
この場合、マスターにはいくつかの欠点があります。ホットスタンバイフィードバック
Evgeny Liskovets 15/09/30

50

ここで述べようにhot_standby_feedback = on

まあ、それの不利な点は、スタンバイがマスターを膨らませることができることです、これは一部の人々にとっても驚くかもしれません

そしてここに

max_standby_streaming_delayの設定は何ですか?デフォルトのhot_standby_feedbackをオンにするのではなく、-1にデフォルト設定したい。このように、スタンバイで行うことはスタンバイにのみ影響します


だから私は追加しました

max_standby_streaming_delay = -1

そしてpg_dump、私たちのためのエラーも、マスター膨らみもありません:)

AWS RDSインスタンスの場合、http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.htmlを確認してください


1
@lennard、これは私のために働いた。この構成をスレーブのpostgresql.confに追加してから、スレーブを再起動しました。
Ardee Aram

13
もちろん、この方法で無制限のレプリカラグを取得できます。レプリケーションスロットを使用してレプリカをマスターに接続している場合、マスターでのxlogの保持が過剰になる可能性があるため、WALアーカイブを使用している場合にのみ実行可能です。
クレイグリンガー

7
AWS RDSでこれをどのように設定しますか?
クリスMP

1
@KrisMP使用はpsql
Yehonatan

4
パラメータグループの@KrisMP-docs.aws.amazon.com
AmazonRDS

13

ホットスタンバイスレーブサーバーのテーブルデータは、長時間実行されているクエリの実行中に変更されます。テーブルデータが変更されないようにするための解決策(PostgreSQL 9.1以降)は、レプリケーションを一時停止し、クエリの後に再開することです。

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume

1
これにはスーパーユーザー権限が必要です。したがって、場合によっては解決策にならないことがあります。
Joao Baltazar、

1
PostgreSQL 10ではxlogに置き換えられたwalため、pg_wal_replay_pause()およびを呼び出しますpg_wal_replay_resume()
ウォンブル、

3

答えには間に合わないかもしれませんが、制作に関しては同じような問題に直面しています。以前はRDSが1つしかなかったため、アプリ側のユーザー数が増えると、そのためにリードレプリカを追加することにしました。ステージングでリードレプリカは正しく機能しますが、本番環境に移行すると、同じエラーが発生し始めます。

そこで、Postgresプロパティのhot_standby_feedbackプロパティを有効にすることでこれを解決します。下記リンクを参考にさせていただきました

https://aws.amazon.com/blogs/database/best-practices-for-amazon-rds-postgresql-replication/

お役に立てば幸いです。


2

上記の@ max-malyshの優れた回答に、更新された情報と参照をいくつか追加します。

つまり、マスターで何かを行う場合は、スレーブで複製する必要があります。PostgresはこれにWALレコードを使用します。これは、マスターでログに記録されたすべてのアクションの後にスレーブに送信されます。その後、スレーブはアクションを実行し、2つは再び同期します。いくつかのシナリオの1つでは、WALアクションでマスターから受信するものとスレーブで競合する可能性があります。それらのほとんどで、WALアクションが変更したいものと競合するトランザクションがスレーブで発生しています。その場合、2つのオプションがあります。

  1. WALアクションの適用を少し遅らせて、スレーブが競合するトランザクションを完了できるようにしてから、アクションを適用します。
  2. スレーブで競合するクエリをキャンセルします。

#1と2つの値に関心があります。

  • max_standby_archive_delay -これは、現在のデータではないWALアーカイブからデータが読み取られているときに、マスターとスレーブ間の長い切断後に使用される遅延です。
  • max_standby_streaming_delay -WALエントリがストリーミングレプリケーションを介して受信されたときにクエリをキャンセルするために使用される遅延。

一般に、サーバーが高可用性レプリケーションを対象としている場合は、これらの数値を短くする必要があります。これには、デフォルト設定30000(単位が指定されていない場合はミリ秒)で十分です。ただし、非常に長時間実行されるクエリが含まれる可能性があるアーカイブ、レポートレプリカ、またはリードレプリカなどを設定する場合は、クエリをキャンセルしないように、これをより高い値に設定する必要があります。上記の推奨900s設定は、良い出発点のようです。私は、無限の値-1を設定することを良いアイデアとして公式のドキュメントに同意しません-バグのあるコードを覆い、多くの問題を引き起こす可能性があります。

実行時間の長いクエリとこれらの値を高く設定することについての注意点の1つは、WALアクションの遅延の原因となっている実行時間の長いクエリと並行してスレーブで実行されている他のクエリは、長いクエリが完了するまで古いデータを参照することです。開発者はこれを理解し、同時に実行すべきではないクエリをシリアル化する必要があります。

方法max_standby_archive_delaymax_standby_streaming_delay機能、および理由の詳細については、こちらをご覧ください


1

同様に、@ max-malyshの優れた回答について、@ Artif3xで詳しく説明した2つ目の警告は、上記の両方です。

マスターからのトランザクションの適用が遅れると、フォロワーにはデータの古い古いビューが表示されます。したがって、max_standby_archive_delayとmax_standby_streaming_delayを設定してフォロワーのクエリが完了するまでの時間を提供することは理にかなっていますが、次の両方の警告に留意してください。

バックアップのフォロワーの値がホスティングクエリとの競合が多すぎる場合、1つのソリューションは複数のフォロワーであり、それぞれが一方または他方に対して最適化されます。

また、複数のクエリを続けて実行すると、walエントリの適用が遅延し続ける可能性があることに注意してください。したがって、新しい値を選択するときは、1つのクエリの時間だけではなく、競合するクエリが開始するたびに開始し、walエントリが最終的に適用されるときに終了する移動ウィンドウです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.