ホットスタンバイを使用した際の問い合わせコンフリクトの処理について
1. はじめに
プライマリインスタンスで実行される一部のスロークエリが原因で、CPU使用率が上昇し、その他のクエリにまで影響を及ぼす現象が発生することがありました。
そこで、負荷の高い参照クエリのみをホットスタンバイで実行し、プライマリインスタンスの負荷を分散する対応を検討しました。
調査を行っていく中で、ホットスタンバイ上での参照クエリとプライマリのデータに追従するための適用処理が衝突する現象が発生することを知りました。
本記事では、その「問い合わせコンフリクト」の現象について説明します。
なお、RDBMSとして PostgreSQL を前提とします。
2. 前提知識
ホットスタンバイで発生するコンフリクトを理解する上での前提知識にさらっと触れていきます。
2-1. スタンバイ
高可用化と負荷分散を実現するために、データの更新ができるサーバ = プライマリ のデータ変更を追跡するサーバを「スタンバイ」または「スレーブ」と呼びます。
PostgreSQLで構成できるスタンバイは、どのような状態で動作しているかの違いによって下記の3つと定義されます。
.BVhmo_Vf_ZufrPD.webp)
内部構造から学ぶPostgreSQL―設計・運用計画の鉄則 p.170
これらは目的によって使用方法が異なり、スタンバイでの参照可否だけでなく、問題発生時にプライマリからスタンバイに切り替える時間や運用手順などに違いがあります。
これらは目的によって使用方法が異なり、スタンバイでの参照可否だけでなく、問題発生時にプライマリからスタンバイに切り替える時間や運用手順などに違いがあります。
ホットスタンバイでは、プライマリから送られてくる変更内容を反映しながら、スタンバイ側でも参照クエリを実行できます。
- アプリケーションからの参照クエリを実行する
- プライマリから届いた変更内容を反映する
この2つが同時に行われる点が、後述すコンフリクトを理解する上で重要になります。
2-2. ストリーミングレプリケーション
ストリーミングレプリケーションは、PostgreSQL本体に備わったレプリケーション機能です。
プライマリーサーバーの更新情報を、リアルタイムでスタンバイサーバーに転送することで、プライマリーサーバーとスタンバイサーバーのデータベースを同じ状態に保つことができます
WALをファイル単位ではなく、変更内容 (WALレコード)単位で送り、粒度の細かいレプリケーションが可能なことから、 「流れ」 を意味する 「ストリーミング」 と名付けられています。
プライマリとスタンバイは常に完全に同じ状態になるわけではありません。
プライマリで更新が発生してから、スタンバイでその変更が反映されるまでには、多少の遅れが発生する可能性があります。
この遅れを 「レプリケーション遅延」 と呼びます。
2-3. WAL (Write Ahead Logging)
WALは、データベースの性能を担保しつつ、データの永続性を保証するための仕組みです。
この仕組みでは、更新トランザクションの内容をいきなりデータファイルへ書き込むのではなく、まず変更内容を WAL として記録します。
WAL に変更内容を先に記録しておくことで、更新のたびにデータ本体のファイルを同期的に書き込む必要がなくなります。データ本体への反映は後からまとめて行えるため、性能を保ちつつ、障害時には WAL を再適用することでデータの整合性を保証できます。
また、レプリケーションにおいても WAL は重要な役割を持ちます。
プライマリで発生した INSERT / UPDATE / DELETE などの変更内容は WAL として記録され、その WAL がスタンバイへ送られます。
スタンバイは受け取った WAL を順番に適用することで、プライマリの状態に追従します。
つまり、ホットスタンバイでは次のような流れでデータが反映されます。
- プライマリで更新が発生する
- 更新内容が WAL に記録される
- WAL がホットスタンバイへ送られる
- ホットスタンバイが WAL を適用する
- ホットスタンバイのデータがプライマリに近い状態へ更新される
このように、ホットスタンバイは読み取り専用のDBとして利用できますが、裏側では常にプライマリから届く WAL を適用し続けています。
そのため、ホットスタンバイ上で実行中の参照クエリと、WAL の適用処理が衝突することがあります。
3. コンフリクトの現象と対応策
こんなイメージでコンフリクトします。

【豆知識】スタンバイ側の参照処理で発生したコンフリクトを解決したい - FUJITSU
プライマリでのロック取得、データベースやテーブル空間の削除、VACUUMによるメンテナンスがコンフリクトを引き起こします。
たとえば、プライマリ側で VACUUM によって不要な行を回収しようとしている一方で、ホットスタンバイ側の長時間クエリがその行をまだ参照している場合、WAL の適用と参照クエリが衝突します。
コンフリクトが発生した場合、PostgreSQL は一定時間だけ WAL の適用を待ちます。
しかし、待機時間を超えてもコンフリクトが解消されない場合、ホットスタンバイ側の参照クエリはキャンセルされます。
デフォルトでは、この待機時間は 30 秒です。
3-1. 対応策の候補
ホットスタンバイ上のクエリコンフリクトへの対応策として、次の2つのパラメータの変更を検討しました。
1つ目は、max_standby_streaming_delay を調整する方法です。
max_standby_streaming_delay は、ストリーミングレプリケーションで受信した WAL の適用と、ホットスタンバイ上の参照クエリが競合した場合に、どれだけ待ってから参照クエリをキャンセルするかを決める設定です。
この値を長くすると、ホットスタンバイ上の参照クエリがすぐにキャンセルされにくくなります。
2つ目は、hot_standby_feedback を有効にする方法です。
hot_standby_feedback を有効にすると、ホットスタンバイ側で実行中のクエリ情報をプライマリへ伝えるようになります。
これにより、プライマリ側の VACUUM が、ホットスタンバイ側のクエリに必要な古い行をすぐに削除しないようになります。
その結果、VACUUM に起因するクエリコンフリクトを抑制できます。
3-2. 対応策の比較
今回の対応では、次の観点で2つの方法を比較しました。
最終的に max_standby_streaming_delay を選択しました。
| 対応策 | メリット | デメリット |
|---|---|---|
max_standby_streaming_delay を調整する | • プライマリ側への副作用が小さい。 • 待機時間の上限を決められる。 | • 待機中は WAL の適用が遅れるため、レプリケーション遅延が発生する。 • 設定時間を超えるとクエリはキャンセルされる。 |
hot_standby_feedback を有効にする | • VACUUM によるコンフリクトを抑制できる。 | • プライマリ側の不要行削除が遅れる。 • テーブルやインデックスの肥大化につながる可能性がある。 • プライマリ側に副作用が出る。 |
3-3. max_standby_streaming_delay を選択した理由
- プライマリインスタンスに副作用を出したくない
- 対象スロークエリでは、レプリケーション遅延によるデータの鮮度は気にしない
上記理由で、max_standby_streaming_delay のパラメータを変更することに決めました。
特に今回の目的は、プライマリインスタンスの負荷を下げること だったので、プライマリ側に副作用が出やすい hot_standby_feedback は採用しませんでした。
ただし、max_standby_streaming_delay = -1 のように無期限で待機させる設定にはしません。
無期限に待機させると、長時間クエリによって WAL の適用が止まり続け、ホットスタンバイがプライマリから大きく遅れる可能性があります。
そのため、今回は max_standby_streaming_delay に有限の値を設定し、次のバランスを取る方針にしました。
- ホットスタンバイ上の重い参照クエリをすぐにキャンセルしない
- ただし、WAL 適用の遅延が無制限に広がることは避ける
- プライマリ側の VACUUM やデータ肥大化には影響を与えない
つまり、今回の方針は プライマリへの副作用を避けつつ、ホットスタンバイ側で許容できる範囲だけ WAL 適用を待たせる というものです。
4. まとめ
今回は、プライマリインスタンスの負荷を下げるために、負荷の高い参照クエリのみをホットスタンバイで実行する対応を検討しました。
その過程で学んだ「問い合わせコンフリクト」の対応策としては、プライマリ側への副作用が出やすい hot_standby_feedback は採用せず、max_standby_streaming_delay によってホットスタンバイ側の待機時間を調整する方針としました。
ホットスタンバイを活用する際は、クエリの実行時間・レプリケーション遅延・プライマリへの影響を考慮することが重要です。
参照
[改訂3版]内部構造から学ぶPostgreSQL | 技術評論社
26.4. ホットスタンバイ
docs.fujitsu/documents/2-00171/postgres-tech-streaming-replication-conflict-error.pdf
PostgreSQLのアーキテクチャー概要 | 富士通