他のバージョンの文書 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

25.5. ホットスタンバイ

ホットスタンバイという単語は、サーバがアーカイブリカバリを実行している最中にサーバに接続し読み取り専用の問い合わせを実行することができる機能を説明するために使われます。 これは、レプリケーションという目的およびバックアップからのリストアの両方で高い精度で好ましい状態にするために有用です。 ホットスタンバイという単語はまた、ユーザが問い合わせを実行しながら、または、開いている接続を維持しながら、またはその両方で、サーバをリカバリ状態から通常の動作に移すことができる機能も示すものです。

ホットスタンバイモードにおける問い合わせは、通常の問い合わせに類似していますが、利用上および管理上の差異が多少あり、以下に説明します。

25.5.1. ユーザのための概説

スタンバイサーバでhot_standbyパラメータが真に設定されている場合、リカバリによりシステムが一貫性を持つようになった後接続を受け付け始めます。 こうした接続はすべて読み取り専用に限定されます。 一時テーブルであっても書き込むことはできません。

スタンバイ上のデータはプライマリサーバから届くまでに多少の時間がかかります。 このため、プライマリとスタンバイの間にはある程度の遅延があります。 したがって、同じ問い合わせをほとんど同時にプライマリとスタンバイに対して実行すると、異なる結果が返る可能性があります。 スタンバイ上のデータはプライマリに対して最後には一貫性を持つといいます。 あるトランザクションのコミットレコードがスタンバイ上で再生されると、そのトランザクションでなされた変更はスタンバイで獲得されるすべての新規スナップショットで可視になります。 現在のトランザクション隔離レベルに応じて、スナップショットは各問い合わせの開始時または各トランザクションの開始時に獲得されます。 詳細については項13.2を参照してください。

ホットスタンバイ中に開始されたトランザクションは以下のコマンドを発行することができます。

ホットスタンバイ中に開始したトランザクションではトランザクションIDを割り当てられません。 また、システムのログ先行書き込みに書き出すことができません。 このため、以下の動作はエラーメッセージを生成します。

通常の操作では、"読み取り専用"トランザクションにはシーケンスの更新およびLISTENUNLISTENNOTIFYの使用が許可されています。 ホットスタンバイセッションの操作では、通常の読み取り専用セッションよりも少し厳しい制約を受けます。 将来のリリースではこの制約の一部が緩和されるかもしれません。

ホットスタンバイ中は、transaction_read_onlyパラメータは常に真であり、変更することはできません。 しかし、データベースを変更するような試行がない限り、ホットスタンバイ中の接続は他のデータベース接続とほとんど同じように動作します。 もし、フェールオーバまたはスイッチオーバが発生すると、データベースは通常処理モードに切り替わります。 サーバのモードが変わってもセッションは接続を保持します。 ホットスタンバイが完了すると、読み書き可能なトランザクションを(ホットスタンバイ中に始まったセッションからであっても)始められるようになります。

ユーザはSHOW transaction_read_onlyを発行することで、そのセッションが読み取り専用かどうかを調べることができます。 さらに、ユーザがスタンバイサーバに関する情報にアクセスできる関数群(表9-66)があります。 これらによりデータベースの現状認識を行うプログラムを作成することができます。 これらを使用して、リカバリの進行状況を監視するために使用したり、データベースを特定の状態にリストアする複雑なプログラムを作成したりすることができます。

25.5.2. 問い合わせコンフリクトの処理

プライマリサーバとスタンバイサーバは、多方面でゆるく結合しています。 プライマリサーバの動作はスタンバイサーバに影響します。 その結果、負の相互作用またはコンフリクトの可能性があります。 最も分かりやすいコンフリクトは性能です。 プライマリサーバで巨大なデータがロードされた場合、スタンバイサーバにおいて同様に巨大なWALレコードが生成されるので、スタンバイサーバにおける問い合わせは互いにI/Oなどのシステム資源を奪い合います。

ホットスタンバイで発生する可能性があるコンフリクトの種類には他にもあります。 これらのコンフリクトは、問い合わせをキャンセルしなければならない可能性があり、解消させるためにはセッションの接続を閉ざすことになる場合もあるため、致命的なコンフリクトです。 ユーザにはこうしたコンフリクトを扱うための複数の方法が提供されます。 コンフリクトする状況には以下があります。

プライマリサーバでは、こうした状況は単に待たされるだけです。 ユーザはコンフリクトする操作をキャンセルすることを選ぶことができます。 しかし、スタンバイ側には選択肢がありません。 WALに記録された操作はすでにプライマリで発生したものですので、スタンバイではその適用に失敗してはなりません。 さらに、適用したいWALを無制限に待機させることを許すことは、まったく望まない結果になってしまうかもしれません。 なぜなら、スタンバイの状態がプライマリの状態とだんだんとかけ離れてしまうからです。 したがって適用すべきWALレコードとコンフリクトするスタンバイの問い合わせを強制的に取り消す仕組みが用意されています。

この問題の例として、スタンバイサーバで現在問い合わせ対象となっているテーブルをプライマリサーバでDROP TABLEを行う管理者を考えてみます。 スタンバイでDROP TABLEが適用されたら問い合わせを継続できないことは明確です。 プライマリ上でこうした状況が発生した場合は、他の問い合わせが終わるまでDROP TABLEは待機させられます。 しかし、DROP TABLEがプライマリで実行された時、プライマリ側でスタンバイで稼動する問い合わせに関する情報がありませんので、スタンバイ側のこうした問い合わせを待機させることはできません。 スタンバイ側で問い合わせが実行している時にWALの変更レコードがスタンバイに届けば、コンフリクトが発生します。 スタンバイサーバはWALレコードの適用を遅延させる(およびその後の適用すべても遅延させる)か、DROP TABLEを適用できるようにコンフリクトする問い合わせを取り消すかのいずれかを行わなければなりません。

コンフリクトする問い合わせが短ければ、適用したいWALを多少遅延させることで、問い合わせを完了させることが通常望まれます。 しかし、WALの適用が長く遅延することはたいていは望まれません。 したがって、取り消し機能はmax_standby_archive_delaymax_standby_streaming_delayというパラメータを持ちます。 これらはWAL適用に許される遅延を定義するものです。 コンフリクトする問い合わせは、何らかの新しく受信したWALデータを適用するための各種遅延設定を超えたら取り消されます。 アーカイブからWALデータを読み取る場合(つまりベースバックアップからの初期リカバリや大きく遅延したスタンバイサーバの"追従")とストリーミングレプリケーションとで異なる遅延値を指定することができるように2つのパラメータが存在します。

主に高可用性のために存在するスタンバイサーバでは、スタンバイ側の問い合わせによって発生する遅延のためにプライマリと大きく遅延が発生することがないように、遅延パラメータを相対的に短く設定することが最善です。 しかし、スタンバイサーバが長時間かかる問い合わせを実行するためのものであれば、長い遅延もしくは制限を設けないことが好まれるかもしれません。 しかし、長時間かかる問い合わせがWALレコードの適用を遅延させてしまう場合、スタンバイサーバ上の他のセッションがプライマリにおける最近の変更を参照することができなくなることは覚えておいてください。

max_standby_archive_delayまたはmax_standby_streaming_delayで指定した遅延を超えると、コンフリクトする問い合わせは取り消されます。 通常これは単なる取り消しエラーという結果となりますが、DROP DATABASEを再生する場合では、コンフリクトするセッション全体が終了します。 また、コンフリクトが待機中のトランザクションで保持されるロックについてのものであれば、そのコンフリクトするセッションが終了します(この動作は将来変更されるかもしれません)。

ユーザは取り消された問い合わせをすぐに再試行するかもしれません(もちろん新規のトランザクション開始後に)。 問い合わせの取り消しは、再生されるWALレコードの性質に依存するので、取り消された問い合わせが再度実行された場合には正常に動作するかもしれません。

遅延パラメータはスタンバイサーバでWALデータを受信してからの経過時間と比べられることに注意してください。 したがって、スタンバイ上で任意の問い合わせに許される猶予期間は、この遅延パラメータよりも大きくなることは決してありません。 これまでの問い合わせを完了させるために待機した結果、あるいは、大量の更新負荷に追従することができなくなった結果、スタンバイがすでに遅延している場合は相当小さくなります。

スタンバイ側の問い合わせとWAL再生の間でもっともよくあるコンフリクト理由は"早すぎる消去"です。 通常PostgreSQLはMVCC規則にしたがって正確なデータの可視性を確実にするために、古い行バージョンを参照するトランザクションが存在しない場合それらを消去することが許されています。 しかし、この規則はマスタ上で実行するトランザクションのみに適用させることができます。 したがって、スタンバイ上のトランザクションでまだ可視である行バージョンを、マスタ上の消去処理が削除してしまう可能性があります。

熟練したユーザは、行バージョンの消去と行バージョンの凍結の両方ともスタンバイ側の問い合わせとコンフリクトする可能性があることに気づくはずです。 手作業でのVACUUM FREEZEは、更新または削除された行がないテーブルであったとしてもコンフリクトを発生し易いものです。

プライマリサーバにおいて規則的かつ頻繁に更新されるテーブルは、スタンバイサーバにおける問い合わせの取り消しの原因になりやすいことを利用者は理解するべきです。 そのような場合、max_standby_archive_delayまたはmax_standby_streaming_delayの設定値はstatement_timeoutの設定と同様に考えることができます。

スタンバイのクエリが中断される受け入れがたいほど多い場合、この問題を解決する方法が用意されています。 1つ目の選択肢は、hot_standby_feedbackパラメータを設定することです。 これはVACUUMによる最近不要になった行の削除を防止しますので、消去によるコンフリクトが発生しません。 これを行う場合、プライマリで不要になった行の消去が遅延することに注意が必要です。望まないテーブルの膨張が発生してしまうかもしれません。 しかし、スタンバイ側で行うべき問い合わせをプライマリサーバ上で直接実行することと比べ、こうした消去に関する問題を優先する価値はありません。 また、スタンバイに実行負荷を分散できるという利点があります。 スタンバイサーバが接続、切断を頻繁に繰り返す場合、hot_standby_feedbackによるフィードバックが提供されていなければ、その値を調整したいと思うでしょう。 例えば、max_standby_archive_delayが増大し、切断している期間WALアーカイブのコンフリクト発生による問い合わせの中断が速やかに行われないことを考えてみてください。また、再接続後に速やかに問い合わせが中断されることを避けるためにmax_standby_streaming_delayを大きくすることを考えてみてください。

他の選択肢は、不要になった行が通常よりも早く消去されないようにプライマリサーバでvacuum_defer_cleanup_ageを増やすことです。 これにより、max_standby_streaming_delayを長くすることなく、スタンバイでキャンセルが起こるようになる前により多くの時間、問い合わせを実行することができます。 しかし、vacuum_defer_cleanup_ageはプライマリサーバ上で実行されたトランザクションを単位に測定されますので、この方法では特定の実行期間を保証することは困難です。

問い合わせキャンセルの個数とその原因はスタンバイサーバ上のpg_stat_database_conflictsシステムビューを用いて参照することができます。 またpg_stat_databaseシステムビューには要約された情報が含まれます。

25.5.3. 管理者のための概説

postgresql.confにおいてhot_standbyonに設定されかつrecovery.confが存在すれば、サーバはホットスタンバイモードで稼動します。 しかし、サーバはまず問い合わせが実行できる程度の一貫性を持つ状態を提供するために十分なリカバリを完了させなければなりませんので、ホットスタンバイでの接続が有効になるまでに多少の時間がかかるかもしれません。 サーバの準備ができたことを確認するために、アプリケーションで接続試行を繰り返すか、サーバログに以下のメッセージがあるかどうかを確認します。

LOG:  entering standby mode

... 多少時間が経過して ...

LOG:  consistent recovery state reached
LOG:  database system is ready to accept read only connections

一貫性に関する情報はプライマリでチェックポイント毎に一度記録されます。 プライマリでwal_levelhot_standbyもしくはlogicalに設定されていない間に書き込まれたWALを読み取っている時、ホットスタンバイを有効にすることはできません。 また、一貫性のある状態への到達は、以下の両方が存在する間遅延することがあります。

ファイルベースのログシッピング(「ウォームスタンバイ」)を実行しているのであれば、次のWALファイルが届く、長くともプライマリのarchive_timeout設定まで待機しなければなりません。

プライマリサーバにおける設定値が変更した場合、スタンバイサーバにおいて数個のパラメータの再設定が必要です。 スタンバイサーバにおける設定値は、プライマリサーバにおける設定値以上でなければなりません。 所定値未満の設定の場合、スタンバイは起動を取りやめます。 所定値以上の設定により、スタンバイサーバは再起動してリカバリが再び開始されます。 このパラメータは以下です。

max_standby_archive_delayおよびmax_standby_streaming_delayの値が適切であるように管理者が選択することが重要です。 最善の選択は業務上の優先順位によって変化します。 例えば、サーバが主に高可用性を目的としたサーバとして作業するものであれば、短い遅延を設定したいでしょう。 非常に積極的な設定ですが、ゼロにしたいかもしれません。 スタンバイサーバが意思決定支援のための問い合わせ用の追加サーバとして作業するものであれば、数時間程度の最大の遅延値の設定、あるいは問い合わせの完了を永遠に待つことを意味する-1という設定でさえ、許容範囲であるかもしれません。

プライマリ側で「ヒントビット」として書き出されたトランザクション状態はWALに記録されません。 このためスタンバイ側のデータはスタンバイ側でヒントを再度書き出すことになります。 ユーザは大規模なソート用の一時ファイルを書き出し、relcache情報ファイルを再作成します。 したがって、ホットスタンバイモードではデータベースのすべてが本当に読み取り専用ではありません。 また、ローカルでは読み取り専用のトランザクションであってもdblinkモジュールを使用したリモートデータベースへの書き出しや、その他のPL関数を使用したデータベース外部への操作が可能であることに注意してください。

リカバリモードの間、下記の管理者用コマンドは受理されません。

繰り返しますが、これらのコマンドの一部は、プライマリサーバにおける「読み取り専用」モードのトランザクションで実際に許可されていることに注意してください。

その結果、スタンバイ側にのみ存在する追加のインデックスやスタンバイ側にのみ存在する統計情報を作成することはできません。 これらの管理者用コマンドが必要な場合、プライマリ側で実行しなければなりません。 最終的にこの変更はスタンバイ側に伝播します。

pg_cancel_backend()pg_terminate_backend()は利用者のバックエンドでは実行できますが、リカバリを実行する起動プロセスでは実行できません。 pg_stat_activityは起動プロセスのエントリを表示しないし、リカバリトランザクションが実行中かどうかも表示しません。 その結果、リカバリの間pg_prepared_xactsは常に空となります。 準備した確信のもてないトランザクションの状態を解明したい場合、プライマリサーバにおいてpg_prepared_xactsを表示するビューを作成し、ビューに解明のためのコマンドを発行してください。

pg_locksは通常通りバックエンドで保持されるロックを示します。 pg_locksはまた、リカバリによって再生されているトランザクションで保持されるAccessExclusiveLocksのすべてを所有する、起動プロセスで管理される仮想トランザクションも表示します。 起動プロセスはデータベースの変更を行うためのロックを獲得しません。 このため起動プロセスにおいてAccessExclusiveLocks以外のロックはpg_locksでは表示されません。 これらは存在することを想定されているだけです。

存在を検知する情報が単純なので、Nagiosプラグインは稼動します。 一部の報告値が異なった、混乱を招く結果となりますが、check_postgresの監視スクリプトも動作します。 それでも、プライマリで行われるバキュームはその変更をスタンバイに送信します。

リカバリの間WALの制御コマンドは稼動しません。 例えば、pg_start_backuppg_switch_xlogなどです。

pg_stat_statementsも含み、動的に読み込み可能なモジュールは稼動します。

デッドロック検出を含むアドバイザリロックは、通常リカバリにおいて稼動します。 アドバイザリロックはWALに決して記録されないので、プライマリサーバでもスタンバイサーバでもWALの再実行においてコンフリクトが起こらないことに注意してください。 プライマリサーバでアドバイザリロックを取得して、スタンバイサーバで同様のアドバイザリロックを掛けることはできません。 アドバイザリロックは取得したサーバだけに関係するものです。

SlonyLondisteBucardoのようにトリガに基づいたレプリケーションシステムは、スタンバイサーバで全く稼動しません。 しかし、それによる変更がスタンバイサーバに送られるまでは、プライマリサーバにおいて問題なく稼動します。 WALの再実行はトリガに基づいたものではありません。 したがって、データベースへの付加的な書き込みを必要とするか、トリガの使用に依存するものを、スタンバイサーバを中継して他のシステムへ送ることはできません。

一部のUUIDジェネレータは、データベースに新しい状態を書き出すことに依存していない限り動作可能ですが、新しいOIDを割り当てることはできません。

現時点では、読み取り専用のトランザクションでは一時テーブルの作成は許されません。 このため既存のスクリプトが正しく動作しない場合があります。 この制限は将来のリリースで緩和されるかもしれません。 これは、標準SQLとの互換性の問題でもあり、技術的な問題でもあります。

テーブル空間が空の場合だけ、DROP TABLESPACEが成功します。 一部のスタンバイ側のユーザはtemp_tablespacesパラメータを介してテーブル空間を活発に使用しているかもしれません。 テーブル空間に一時ファイルが存在する場合、一時ファイルを確実に削除するためすべての問い合わせが取り消されます。 このため、WAL再生を続けながらテーブル空間を削除することができます。

プライマリサーバにおけるDROP DATABASEまたはALTER DATABASE ... SET TABLESPACEの実行により、スタンバイサーバのデータベースに接続するすべてのユーザを強制的に接続を切断させることになるWALエントリを生成します。 これはmax_standby_streaming_delayの設定にかかわらず、直ちに起こります。 ALTER DATABASE ... RENAMEはユーザを切断しないので大部分の場合は気がつきませんが、プログラムがデータベースの名称に依存するときは混乱の原因となることに注意してください。

通常の(リカバリ以外の)モードで、ログイン権限を持つロールが接続している間にそのロールにDROP USERまたはDROP ROLEを発行した場合、接続中のユーザには何も起こらず、接続し続けます。 しかし、そのユーザは再接続できません。 この振舞いはリカバリモードでも適用されます。 このためプライマリ側でDROP USERされたとしても、スタンバイ側のユーザの接続は切断されません。

リカバリの間も統計情報は収集されます。 すべてのスキャン、読み取り、ブロック、インデックスの使用などは、スタンバイサーバにおいて正常に記録されます。 再実行によりプライマリサーバの結果が重複して収集されることはないので、行の挿入によりpg_stat_user_tablesの挿入列の値は増加しません。 リカバリの開始時点で統計情報ファイルが削除されるので、プライマリサーバとスタンバイサーバで統計情報は異なります。 これは将来どうするか検討中であり、バグではありません。

リカバリの間は自動バキュームは稼動しません。 リカバリが終わると正常に起動します。

リカバリの間バックグラウンドライタは稼動して(プライマリサーバにおけるチェックポイントに類似した)リスタートポイントを設定し、通常のブロック消去を行います。 これはスタンバイサーバに保存されるヒントビット情報の更新を含むことができます。 リカバリの間CHECKPOINTコマンドは受理されますが、新規のチェックポイントではなくてリスタートポイントが設定されます。

25.5.4. ホットスタンバイパラメータリファレンス

種々のパラメータが上記項25.5.2および項25.5.3で述べられています。

プライマリサーバでは、wal_levelおよびvacuum_defer_cleanup_ageのパラメータを使用できます。 プライマリサーバにmax_standby_archive_delayおよびmax_standby_streaming_delayを設定しても無効です。

スタンバイサーバではhot_standbymax_standby_archive_delaymax_standby_streaming_delayのパラメータを使用できます。 サーバがスタンバイモードの間vacuum_defer_cleanup_ageを設定しても無効です。 しかし、スタンバイサーバがプライマリサーバになった場合、意味を持つようになります。

25.5.5. 警告

ホットスタンバイには幾つかの制限があります。 将来のリリースでは改善されると思われます。