RDS for PostgreSQL DB インスタンスのリードレプリカをクエリするときに、「canceling statement due to conflict with recovery」(リカバリとの競合のため、ステートメントをキャンセルしています) というエラーをトラブルシューティングするにはどうすればよいですか?

所要時間2分
0

Amazon Relational Database Service (Amazon RDS) for PostgreSQL インスタンス用にリードレプリカを設定しました。リードレプリカにクエリを実行すると、「canceling statement due to conflict with recovery」(リカバリとの競合のため、ステートメントをキャンセルしています) というエラーが表示されます。

簡単な説明

このエラーは、リードレプリカで発生しているアクティビティをプライマリインスタンスから認識できないことが原因で発生する可能性があります。リカバリとの競合は、変更がリードレプリカで行われているアクティビティを妨げる可能性があるため、WAL 情報をリードレプリカに適用できない場合に発生します。

例えば、プライマリインスタンスでドロップされたテーブルのリードレプリカで長時間実行される SELECT ステートメントが実行されているときに、プライマリインスタンスで DROP ステートメントを実行するとします。その場合、リードレプリカには次の 2 つのオプションがあります。

  • SELECT ステートメントが終了するのを待ってから、WAL レコードを適用します。この場合、レプリケーションの遅延が長くなります。
  • WAL レコードを適用し、SELECT ステートメントをキャンセルします。この場合、「canceling statement due to conflict with recovery」(リカバリとの競合のため、ステートメントをキャンセルしています) というエラーが表示されます。

リードレプリカは、max_standby_streaming_delay および max_standby_archive_delay パラメータの値に基づいて、これらのレプリケーションの競合を解決します。max_standby_streaming_delay パラメータは、適用されようとしている WAL エントリと競合するスタンバイクエリをキャンセルする前に、リードレプリカが待機する時間を決定します。競合するステートメントがこの期間を過ぎても実行されている場合、PostgreSQL はステートメントをキャンセルし、次のエラーメッセージを発行します:

ERROR: canceling statement due to conflict with recovery

このエラーは通常、リードレプリカで長時間実行されるクエリが原因で発生します。

前述の DROP ステートメントの例では、DROP リクエストは WAL ファイルに保存され、整合性を保つために後でリードレプリカに適用します。max_standby_streaming_delay の値を超えるランタイムで、ドロップされたオブジェクトからデータを取得しようとするリードレプリカで SELECT ステートメントが既に実行されているとします。その後、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」(DETAIL: ユーザーがリレーションロックを保持していた時間が長過ぎます) というエラーが表示される

max_standby_streaming_delay/max_standby_archive_delay: これらのパラメータを使用すると、適用されようとしている WAL エントリと競合するスタンバイステートメントをキャンセルするまでの時間を長くすることができます。これらの値は、プライマリインスタンスからデータを受信した後、WAL データを適用するために許可される合計時間を表します。これらのパラメータは、WAL データの読み取り元に応じて指定されます。WAL データがストリーミングレプリケーションから読み取られる場合は、max_standby_streaming_delay パラメータを使用します。WAL データが Amazon Simple Storage Service (Amazon S3) のアーカイブの場所から読み取られる場合は、max_standby_archive_delay パラメータを使用します。

これらのパラメータを設定するときは、次の点に注意してください。

  • これらのパラメータの値を -1 に設定すると、レプリカインスタンスは競合するクエリが完了するまで永久に待機することができ、レプリケーションの遅延が増大します。
  • これらのパラメータの値を 0 に設定すると、競合するクエリがキャンセルされ、WAL エントリがレプリカインスタンスに適用されます。
  • これらのパラメータのデフォルト値は 30 秒に設定されています。
  • これらのパラメータを設定する際に単位を指定しない場合、ミリ秒が単位とみなされます。

これらのパラメータの値を調整して、ユースケースに基づいてクエリのキャンセルまたはレプリケーションの遅延のバランスを取ります。

注: WAL アーカイブエントリの読み取りと競合するクエリをキャンセルしないように max_standby_archive_delay を増やす場合は、WAL エントリのストリーミングとの競合に関連するキャンセルを避けるために max_standby_streaming_delay も増やすことを検討してください。

「canceling statement due to conflict with recover」(リカバリとの競合のため、ステートメントをキャンセルしています) というエラーとともに「DETAIL: User query might have needed to see row versions that must be removed」(DETAIL: 削除する必要がある行バージョンを表示するためにユーザークエリが必要だった可能性があります) というエラーが表示される

hot_standby_feedback: このパラメータをアクティブ化すると、最も古いアクティブなトランザクションの情報とともに、フィードバックメッセージがリードレプリカからプライマリインスタンスに送信されます。したがって、プライマリインスタンスは、トランザクションが必要とする可能性のあるレコードを削除しません。

リードレプリカでこのパラメータをアクティブ化すると、リードレプリカで長時間実行されるクエリにより、プライマリインスタンスでテーブルの肥大化が生じる可能性があります。これは、バキュームオペレーションでは、リードレプリカで実行されているクエリで必要になる可能性のあるデッドタプルが削除されないためです。このパラメータはデフォルトではオフになっています。したがって、このパラメータをアクティブ化する場合は注意が必要です。

また、リードレプリカの pg_stat_database_conflicts ビューで、リードレプリカのリカバリとの競合を理由としてキャンセルされたステートメントに関する統計情報を調べることもできます。


AWS公式
AWS公式更新しました 2年前
コメントはありません

関連するコンテンツ