継続的なアーカイブ処理を使用して、プライマリサーバが失敗した場合に操作を引き継ぐ準備がなされた、1つ以上のスタンバイサーバを持つ高可用性(HA)クラスタ構成を作成することができます。 この機能はウォームスタンバイまたはログシッピングとして広く知られています。
プライマリサーバとスタンバイサーバは、この機能を提供するために共同して稼動しますが、サーバとサーバはゆるく結合しています。 プライマリサーバは継続的アーカイブモードで動作し、各スタンバイサーバはプライマリからWALファイルを読み取る、継続的リカバリモードで動作します。 この機能を可能にするために、データベースのテーブル変更は不要です。 したがって、他のレプリケーションの解法に比べて、管理にかかるオーバーヘッドが減少します。 この構成はプライマリサーバの性能への影響も相対的に減少させます。
あるデータベースサーバから他へ直接WALレコードを移動することは通常、ログシッピングと説明されます。 PostgreSQLはファイルベースのログシッピングを実装します。 つまりWALレコードはある時点で1つのファイル(WALセグメント)として送信されることを意味します。 WALファイル(16MB)は隣り合うシステム、同じサイトの別システム、地球の裏側のシステムなど距離に関わらず、簡単かつ安価に送付することができます。 この技法に必要な帯域幅はプライマリサーバのトランザクションの頻度に応じて変動します。 レコードベースのログシッピングはより粒度を細かくしたもので、ネットワーク接続を介してWALの変更を増分的に流します(26.2.5参照)。
ログシッピングが非同期であることに注意しなければなりません。
つまり、WALレコードはトランザクションがコミットした後に転送されます。
結果として、プライマリサーバが災害などの致命的な失敗をうけた場合、送信されていないトランザクションが失われますので、データを損失する空白期間があります。
ファイルベースのログシッピングにおけるデータ損失の空白期間量をarchive_timeout
パラメータを用いて制限することができます。
これは数秒程度まで小さく設定することができます。
しかし、低く設定するとファイル転送に必要な帯域幅が増大します。
ストリーミングレプリケーション(26.2.5参照)により、データを損失する期間を非常に小さくすることができます。
リカバリ処理の性能は十分よく、一度実施されれば、スタンバイサーバが完全な状態から逸脱するのは一時的にしかすぎません。 結果としてこれは、高可用性を提供するウォームスタンバイ構成と呼ばれます。 保管されたベースバックアップからサーバをリストアし、ロールフォワードを行うことはおそらく長時間かかりますので、これは高可用性のための解法とはいえず、災害からのリカバリのための解法です。 スタンバイサーバは読み取り専用の問い合わせに使用することもできます。 この場合ホットスタンバイサーバと呼ばれます。 詳細については26.5を参照してください。
プライマリサーバとスタンバイサーバを、少なくともデータベースサーバという見地でできる限り同じになるように作成することを通常勧めます。 具体的には、テーブル空間に関連するパス名はそのまま渡されますので、テーブル空間機能を使用する場合には、プライマリとスタンバイサーバの両方でテーブル空間用のマウントパスを同じにしておかなければなりません。 CREATE TABLESPACEをプライマリで実行する場合、そのコマンドを実行する前に必要な新しいマウントポイントをプライマリとすべてのスタンバイサーバで作成しなければならないことに注意してください。 ハードウェアをまったく同じにする必要はありませんが、経験上アプリケーションとシステムの運用期間に渡って2つの同じシステムを管理する方が、異なる2つのシステムを管理するよりも簡単です。 いずれにしてもハードウェアアーキテクチャは必ず同じでなければなりません。 例えば32ビットシステムから64ビットシステムへのシッピングは動作しません。
一般的に、異なるメジャーリリースレベルのPostgreSQL間でログシッピングはできません。 マイナーリリースの更新ではディスク書式を変更しないというのがPostgreSQLグローバル開発グループの方針ですので、プライマリサーバとスタンバイサーバとの間でマイナーリリースレベルの違いがあってもうまく動作するはずです。 しかし、この場合、公的なサポートは提供されません。 できる限りプライマリサーバとスタンバイサーバとで同じリリースレベルを使用してください。 新しいマイナーリリースに更新する場合、もっとも安全な方針はスタンバイサーバを先に更新することです。 新しいマイナーリリースは以前のマイナーリリースのWALファイルを読み込むことはできますが、逆はできないかもしれません。
スタンバイモードでは、サーバは継続的にマスタサーバから受け取ったWALを適用します。
スタンバイサーバはWALアーカイブ(restore_command参照)から、または直接TCP接続(ストリーミングレプリケーション)を介してマスタサーバから、WALを読み取ることができます。
またスタンバイサーバはスタンバイクラスタのpg_wal
ディレクトリにあるすべてのWALをリストアしようと試みます。
これはよくサーバの再起動後、スタンバイが再起動前にマスタから流れ込んだWALを再生する時に発生します。
しかしまたファイルを再生する任意の時点で、手作業でpg_wal
にコピーすることもできます。
起動時、スタンバイサーバはrestore_command
を呼び出して、アーカイブ場所にある利用可能なすべてのWALをリストアすることから始めます。
そこで利用可能なWALの終端に達し、restore_command
が失敗すると、pg_wal
ディレクトリにある利用可能な任意のWALのリストアを試みます。
ストリーミングレプリケーションが設定されている場合、これに失敗すると、スタンバイはプライマリサーバへの接続を試み、アーカイブまたはpg_wal
内に存在した最終の有効レコードからWALのストリーミングを開始します。
ストリーミングレプリケーションが未設定時にこれに失敗する場合、または、接続が後で切断される場合、スタンバイは最初に戻り、アーカイブからのファイルのリストアを繰り返し行います。
このアーカイブ、pg_wal
、ストリーミングレプリケーションからという再試行の繰り返しはサーバが停止する、あるいはトリガファイルによるフェイルオーバーが発行されるまで続きます。
pg_ctl promote
が実行された時、pg_promote()
が呼び出された時、またはトリガファイル(promote_trigger_file
)が存在する時、スタンバイモードは終了し、サーバは通常の動作に切り替わります。
フェイルオーバーの前に、アーカイブまたはpg_wal
内の即座に利用可能なWALをすべてリストアします。
しかし、マスタへの接続を行おうとはしません。
25.3で説明したように、スタンバイからアクセス可能なアーカイブディレクトリに対してプライマリで継続的なアーカイブを設定してください。 このアーカイブ場所はマスタが停止した時であってもスタンバイからアクセス可能でなければなりません。 つまり、マスタサーバ上ではなく、スタンバイサーバ自身上に存在するか、または他の高信頼性サーバ上に存在しなければなりません。
ストリーミングレプリケーションを使用したい場合、スタンバイサーバ(複数可)からのレプリケーション接続を受け付けるようにプライマリサーバで認証を設定してください。
つまり、ロールを作成し適切な項目を提供、あるいは、そのデータベースフィールドとしてreplication
を持つ項目をpg_hba.conf
内に設定してください。
また、プライマリサーバの設定ファイルにおいてmax_wal_senders
が十分大きな値に設定されていることを確認してください。
レプリケーションスロットを使用している場合は、max_replication_slots
も十分に設定されているか確認してください。
25.3.2に記述したように、スタンバイサーバの再起動のために、ベースバックアップを取得してください。
スタンバイサーバを設定するためには、プライマリサーバから取得したベースバックアップをリストアしてください(25.3.4参照)。
スタンバイのクラスタデータディレクトリ内にstandby.signal
ファイルを作成し、standby_mode
を有効にしてください。
WALアーカイブからファイルをコピーする簡単なコマンドをrestore_commandに設定してください。
高可用性のために複数のスタンバイサーバを持たせようとしている場合、recovery_target_timeline
をlatest
に設定し(デフォルト)、スタンバイサーバが他のスタンバイにフェイルオーバーする時に発生するタイムラインの変更に従うようにします。
ここで説明した組み込みのスタンバイモードといっしょにpg_standbyや類似ツールを使用しないでください。 restore_commandはファイルが存在しない場合に即座に終了しなければなりません。 サーバが必要に応じてそのコマンドを再度実行します。 pg_standbyのようなツールを使用するためには26.4を参照してください。
ストリーミングレプリケーションを使用したい場合には、ホスト名(またはIPアドレス)とプライマリサーバとの接続に必要な追加情報を含む、libpq接続文字列でprimary_conninfoを記述してください。 プライマリで認証用のパスワードが必要な場合はprimary_conninfoにそのパスワードも指定する必要があります。
スタンバイサーバを高可用性を目的に設定しているのであれば、スタンバイサーバはフェイルオーバーの後プライマリサーバとして動作しますので、プライマリサーバと同様にWALアーカイブ処理、接続、認証を設定してください。
WALアーカイブを使用している場合、archive_cleanup_commandパラメータを使用してスタンバイサーバで不要となったファイルを削除することで、その容量を最小化することができます。
特にpg_archivecleanupユーティリティは、典型的な単一スタンバイ構成(pg_archivecleanup参照)におけるarchive_cleanup_command
と共に使用されるように設計されています。
しかし、バックアップを目的にアーカイブを使用している場合には、スタンバイから必要とされなくなったファイルであっても、最新のベースバックアップの時点からリカバリするために必要なファイルを保持しなければならないことに注意してください。
簡単な設定例を以下に示します。
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass options=''-c wal_sender_timeout=5000''' restore_command = 'cp /path/to/archive/%f %p' archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
スタンバイサーバの台数に制限はありませんが、ストリーミングレプリケーションを使用するなら、プライマリサーバに同時に接続できるようにmax_wal_senders
を十分な数に設定してください。
ストリーミングレプリケーションによりスタンバイサーバはファイルベースのログシッピングよりもより最近の状態を維持できるようになります。 スタンバイは、WALレコードが生成された時にWALファイルがいっぱいになるまで待機せずにWALレコードをスタンバイに流し出すプライマリと接続します。
ストリーミングレプリケーションはデフォルトで非同期で、(26.2.8参照)
この場合、プライマリでトランザクションがコミットされてから、その変更がスタンバイ側で参照可能になるまでの間にわずかな遅延がまだあります。
しかし、この遅延はファイルベースのログシッピングよりも非常に小さなもので、負荷に追随できる程度の能力があるスタンバイであれば通常は1秒以下です。
ストリーミングレプリケーションでは、データ損失期間を減らすためのarchive_timeout
を必要としません。
ファイルベースの継続的アーカイブのないストリーミングレプリケーションを使用している場合、スタンバイが受け取る前に古いWALセグメントを再利用するかもしれません。
もし、そうなった場合はスタンバイは新しいベースバックアップから再作成しなければならなくなります。
wal_keep_size
を十分に大きくしたり、レプリケーションスロットにスタンバイを設定することでWALセグメントがすぐに再利用されることを防ぎ、これを防ぐことができます。WALアーカイブをスタンバイからアクセスできる位置に設定する場合は、スタンバイが常にWALセグメントを追随することができるため、これらの解決策は要求されません。
ストリーミングレプリケーションを使用するためには、26.2の説明のようにファイルベースのログシッピングを行うスタンバイサーバを設定してください。
ファイルベースのログシッピングを行うスタンバイをストリーミングレプリケーションを行うスタンバイに切り替える手順は、primary_conninfo
設定をプライマリサーバを指し示すように設定することです。
スタンバイサーバがプライマリサーバ上のreplication
疑似データベースに接続できる(26.2.5.1参照)ように、プライマリでlisten_addressesと認証オプション(pg_hba.conf
参照)を設定してください。
キープアライブソケットオプションをサポートするシステムでは、tcp_keepalives_idle、tcp_keepalives_intervalおよびtcp_keepalives_countを設定することで、プライマリの接続切断の即時検知に有用です。
スタンバイサーバからの同時接続数の最大値を設定してください(詳細はmax_wal_sendersを参照)。
スタンバイが起動し、primary_conninfo
が正しく設定されると、スタンバイはアーカイブ内で利用可能なWALファイルをすべて再生した後にプライマリと接続します。
接続の確立に成功すると、スタンバイでwalreceiver
が存在し、プライマリで対応するwalsender
が存在します。
信頼できるユーザのみがWALストリームを読み取ることができるように、レプリケーション用のアクセス権限を設定することは非常に重要です。
WALから機密情報を取り出すことは簡単だからです。
スタンバイサーバはプライマリに対してプライマリのREPLICATION
権限を持つアカウントか、スーパーユーザとして認証されなければなりません。
レプリケーションのためのREPLICATION
権限 と LOGIN
権限を持つ専用のユーザを作成することをお勧めします。
REPLICATION
権限は非常に強力な権限なので、SUPERUSER
のようにプライマリのデータを変更することを許可されていません。
レプリケーション用のクライアント認証はpg_hba.conf
内でそのdatabase
フィールドにreplication
を指定したレコードで制御されます。
例えば、スタンバイがIPアドレス192.168.1.100
のホストで稼動し、レプリケーション用のアカウントの名前がfoo
である場合、管理者はプライマリ上のpg_hba.conf
に以下の行を追加することができます。
# 利用者 foo のホスト 192.168.1.100 からプライマリサーバへのレプリケーションスタンバイとしての接続を # 利用者のパスワードが正しく入力されたならば許可する # # TYPE DATABASE USER ADDRESS METHOD host replication foo 192.168.1.100/32 md5
プライマリサーバのホスト名とポート番号、接続する利用者名およびパスワードは、primary_conninfoで指定します。
パスワードはスタンバイサーバの~/.pgpass
ファイルでも設定できます(database
フィールドのreplication
を指定します)。
例えば、プライマリサーバが稼動するホストの IP アドレスが192.168.1.50
でポート番号が5432
であり、レプリケーションのアカウント名がfoo
であり、パスワードがfoopass
である場合、管理者はスタンバイサーバのpostgresql.conf
ファイルに次行を追加できます。
# プライマリサーバが 192.168.1.50 のホストの 5432ポートで稼動し # 利用者名が foo でパスワードが foopass とする primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
ストリーミングレプリケーションの重要な健全性尺度は、プライマリサーバで生成されたがスタンバイサーバではまだ適用されていないWALレコードの量です。
プライマリサーバの現在のWAL書き込み位置とスタンバイサーバの受理したWALの最終位置を比較すれば、この遅延を計算できます。
これらの位置は、プライマリサーバではpg_current_wal_lsn
を、スタンバイサーバではpg_last_wal_receive_lsn
を使用すれば検索できます(詳細は表 9.85および表 9.86を参照)。
スタンバイサーバの最終位置は、ps
コマンドを使用して WAL受信プロセスの状態としても表示できます(詳細は27.1を参照)。
pg_stat_replication
ビューを介してWAL送信処理プロセスのリストを入手することができます。
pg_current_wal_lsn
とビューのsent_lsn
フィールドとの違いが大きい場合、マスタサーバが高負荷状態であることを示している可能性があります。
一方でスタンバイサーバ上のsent_lsn
とpg_last_wal_receive_lsn
の値の差異は、ネットワーク遅延、またはスタンバイが高負荷状態であることを示す可能性があります。
ホットスタンバイ上では、WAL受信プロセスの状態は、pg_stat_wal_receiver
ビューを通じて入手することができます。
pg_last_wal_replay_lsn
とビューのreceived_lsn
との違いが大きい場合、WALのリプレイを上回る速さでWALが受信されていることを示しています。
レプリケーションスロットは、以下のことを保証する自動的な方法を提供します。 全てのスタンバイがWALセグメントを受け取るまでは、マスターがWALセグメントを削除しないこと、また、スタンバイが接続していない際にも、リカバリの競合が発生する可能性がある行をマスターが削除しないこと、です。
レプリケーションスロットを使う代わりに、wal_keep_sizeを使う、あるいはarchive_commandを使用してセグメントをアーカイブに保存することによっても、古いWALセグメントの削除を防ぐことができます。
しかし、これらの方法はしばしば要求される以上のWALセグメントを残すことになってしまうのに対し、レプリケーションスロットは必要と判断されたセグメントのみを残します。
一方で、レプリケーションスロットはpg_wal
のための領域を埋め尽くす大量のWALセグメントを残してしまうかも知れません。
これらの方法のメリットの一つはpg_wal
が要求する領域を制限できることです。現時点でレプリケーションスロットを使って同じことをする方法はありません。
max_slot_wal_keep_sizeは、レプリケーションスロットによって残されるWALファイルの大きさを制限します。
同様に、hot_standby_feedbackとvacuum_defer_cleanup_ageは必要な行をvacuumが削除するのを防ぐ機能を提供しますが、前者はスタンバイが接続されていない間は行の保護を提供しませんし、後者は適切な保護を提供するために高い値を設定せざるを得ないことがしばしばあります。 レプリケーションスロットはこのような短所を克服しています。
いずれのレプリケーションスロットにも小文字、数字、アンダースコアを含む名前があります。
レプリケーションスロットとその状態はpg_replication_slots
ビューより確認できます。
レプリケーションスロットはストリーミングレプリケーションプロトコル( 52.4参照)もしくはSQL関数(9.27.6参照)を使用し、作成や削除ができます。
以下のような方法でレプリケーションスロットを作成できます。
postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot'); slot_name | lsn -------------+----- node_a_slot | postgres=# SELECT slot_name, slot_type, active FROM pg_replication_slots; slot_name | slot_type | active -------------+-----------+-------- node_a_slot | physical | f (1 row)
スタンバイのレプリケーションスロットを使用できるように設定するためには、primary_slot_name
をスタンバイ側で設定します。
以下は単純な設定例です。:
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass' primary_slot_name = 'node_a_slot'
カスケードレプリケーションは、リレーのような振る舞い、つまり、スタンバイサーバから他のスタンバイにレプリケーション接続し、WALレコードを送信することができます。 マスターサーバへ直接の接続を減らしたり、サイト相互の帯域オーバヘッドを最小化するために使用することができます。
カスケードスタンバイとして知られているとおり、スタンバイは受け取り手としても送り手としても振る舞うことができます。 よりマスターサーバに近いスタンバイサーバは上流サーバと呼ばれるのに対し、より遠いスタンバイサーバは下流サーバと呼ばれます。 カスケードレプリケーションには下流サーバの数に制限は設定されていません。しかし、どのスタンバイサーバも最終的には1つのマスター/プライマリサーバに繋がる1つの上流サーバに接続します。
カスケードスタンバイはマスターから受け取ったWALレコードだけでなく、アーカイブからリストアしたWALレコードも送信します。 このため、レプリケーション接続が上流サーバで切断しても、ストリーミングレプリケーションは下流サーバへ新しいWAL レコードがある限り継続します。
カスケードレプリケーションは現時点では非同期です。同期レプリケーション(参照26.2.8)の設定は現時点でカスケードレプリケーションへは影響を与えません。
ホットスタンバイがどの様に配置されていても、ホットスタンバイフィードバックは上流に伝播します。
上流スタンバイサーバが昇格し、新しいマスターサーバになった場合、recovery_target_timeline
が'latest'
に設定されていれば、下流サーバは新マスターサーバからのストリーミングレプリケーションを継続します(デフォルトです)。
カスケードレプリケーションを使うためには、カスケードスタンバイをセットアップ、つまり、レプリケーション接続を許可してください。(max_wal_sendersとhot_standbyおよび、 クライアント認証を設定してください)
また、下流スタンバイがカスケードスタンバイに接続できるために、下流スタンバイではprimary_conninfo
を設定する必要があります。
PostgreSQLのストリーミングレプリケーションはデフォルトで非同期です。 プライマリサーバがクラッシュした場合、コミットされた一部のトランザクションがスタンバイサーバに複製されず、データ損失を引き起こす可能性があります。 データ損失量はフェイルオーバー時点のレプリケーション遅延に比例します。
同期レプリケーションは、あるトランザクションでなされた変更はすべて、1つ以上の同期スタンバイサーバに転送されていることを確実にする機能を提供します。
これはトランザクションコミットで提供される永続性の標準レベルを拡張します。
この保護レベルはコンピュータ科学理論では、2-safeレプリケーション、そしてsynchronous_commit
がremote_write
に設定されている場合にはgroup-1-safe (group-safeと1-safe) と呼ばれます。
同期レプリケーションを要求する時、書き込みトランザクションのコミットはそれぞれ、そのコミットがプライマリサーバおよびスタンバイサーバの両方で、ディスク上の書き込み先行ログに書き込まれたという確認を受けとるまで待機します。 データ損失が起こる可能性は、プライマリサーバとスタンバイサーバが同時にクラッシュしてしまった場合のみです。 これは非常に高い永続性を提供することができますが、それはシステム管理者が2つのサーバの設置と管理に関して注意を払っている場合のみです。 確認のための待機は、サーバがクラッシュした場合でも変更が失われないということでユーザからの信頼性が大きくなりますが、同時に要求するトランザクションの応答時間も必ず大きくなります。 最小待機時間はプライマリとスタンバイの間の往復遅延時間です。
読み取り専用のトランザクションおよびトランザクションのロールバックはスタンバイサーバからの応答を待つ必要はありません。 副トランザクションのコミットもスタンバイサーバからの応答を待つことはなく、最上位レベルのコミットのみ待機します。 データロード処理やインデックス構築など長時間実行される操作は、最終コミットメッセージまで待機しません。 準備およびコミットの両方を含め、二相コミット動作はすべてコミット待機を必要とします。
同期スタンバイは、物理レプリケーションのスタンバイでも、論理レプリケーションのサブスクライバーのどちらでも構いません。
また同期スタンバイは、適切なフィードバックメッセージを送信する方法を知っている、物理あるいは論理WALレプリケーションストリームの消費者であっても構いません。
組み込みの物理あるいは論理レプリケーションシステムを別にすると、pg_receivewal
とpg_recvlogical
、それにサードパーティーのレプリケーションシステムとカスタムプログラムが該当します。
対応する同期レプリケーションのサポートの詳細に関するドキュメントを参照してください。
一度、ストリーミングレプリケーションが設定されている場合、同期レプリケーションの設定には必要な追加設定は1つだけ:synchronous_standby_namesを空でない値に設定することです。
またsynchronous_commit
はon
に設定されていなければなりませんが、これはデフォルト値ですので、通常は変更する必要はありません。(19.5.1 および19.6.2を参照してください)
この設定によりスタンバイがそのコミットレコードを信頼できるストレージに書き込んだことが確認できるまで、各コミットが待たされるようになります。
synchronous_commit
は個々のユーザによって設定することができます。
このため、トランザクション単位を基準とした永続性の保証を制御するために、設定ファイルの中で特定のユーザまたはデータベースについて設定することも、アプリケーションによって動的に設定することもできます。
コミットレコードがプライマリ上のディスクに書き出された後、WALレコードがスタンバイに送信されます。
スタンバイにてwal_receiver_status_interval
がゼロに設定されていない限り、スタンバイは新しいWALデータの塊がディスクに書き出される度に応答メッセージを返します。
synchronous_commit
がremote_apply
に設定されている場合には、コミットレコードが再生され、そのトランザクションが可視化されたときに応答メッセージを返します。
スタンバイが、プライマリ上のsynchronous_standby_names
にしたがって、同期スタンバイとして選ばれた時は、コミットレコードの受領の確認のために待機しているトランザクションをいつ解放すべきかを決めるために、他の同期スタンバイとともにそれらスタンバイからの応答メッセージが考慮されます。
これらのパラメータにより、管理者はどのスタンバイサーバを同期スタンバイとすべきかを指定することができます。
同期レプリケーションの設定は主にマスタでなされることに注意してください。
指名されたスタンバイは直接マスターサーバに接続される必要があります。
つまり、カスケードレプリケーションを使用している下流スタンバイサーバについて、マスターサーバは何も知りません。
synchronous_commit
をremote_write
に設定することで、個々のコミットは、スタンバイサーバがコミットされたレコードを受け取り、オペレーティングシステムに書きだしたことが確認できるまで待ちますが、スタンバイ上のディスクに吐き出すまでは待ちません。
これは、on
と設定するより、提供される永続性は弱くなります。
具体的には、スタンバイサーバはオペレーティングシステムがクラッシュした場合にデータを失う可能性がありますが、PostgreSQLがクラッシュした場合にはデータを失いません。
しかし、実用的にはこの設定はトランザクションの応答時間を短くすることができるので有用です。
データの損失は、プライマリサーバとスタンバイサーバが同時にクラッシュし、かつ、プライマリのデータベースが同時に壊れた場合にのみ発生します。
synchronous_commit
をremote_apply
に設定することで、現在の同期スタンバイがトランザクションを再生し、ユーザから見えるようにしたと報告するまでは各々のコミットは待たされます。
単純なケースでは、因果一貫性を保つ負荷分散を可能にします。
高速シャットダウンが要求された場合、ユーザは待ち状態ではなくなります。 しかし非同期レプリケーションを使用している時と同じく、送信中のWALレコードが現在接続しているスタンバイサーバに転送されるまで、サーバは完全に停止しません。
同期レプリケーションは、一つ以上の同期スタンバイサーバをサポートします。
同期と見なされるすべてのスタンバイサーバがデータの受領を確認するまで、トランザクションは待機します。
トランザクションが応答を待たなければならない同期スタンバイの数は、synchronous_standby_names
で指定されます。
また、このパラメータには、スタンバイの名前のリストと、リストされたものから同期スタンバイを選ぶ方法(FIRST
とANY
)を指定します。
方法FIRST
は優先度に基づく同期レプリケーションを指定し、優先度に応じて選択された同期スタンバイにWALレコードがレプリケーションされるまで、トランザクションのコミットは待機します。
リストの前の方に名前が書いてあるスタンバイにはより高い優先度が与えられ、同期とみなされます。
リストの後ろの方に書いてあるスタンバイは、潜在的な同期スタンバイであることを示します。
どんな理由であれ、現在のスタンバイのどれかの接続が切断されると、次に優先度が高いスタンバイがとって代わります。
優先度に基づく複数同期スタンバイのためのsynchronous_standby_names
の例を示します。
synchronous_standby_names = 'FIRST 2 (s1, s2, s3)'
この例では、もし4つのスタンバイサーバs1
、s2
、s3
、s4
が稼働中なら、s1
とs2
が同期スタンバイに選ばれます。
それらの名前がスタンバイ名のリストの最初の方にあるからです。
s3
は潜在的な同期スタンバイで、s1
あるいはs2
が故障した時に同期スタンバイの役割を取って代わります。
このリストに名前が載っていないので、s4
は非同期スタンバイです。
方法ANY
はクォーラムに基づく同期レプリケーションを指定し、少なくともリスト中で指定された数の同期スタンバイにWALレコードがレプリケーションされるまで、トランザクションのコミットを待たせます
クォーラムに基づく同期スタンバイのためのsynchronous_standby_names
の例を示します。
synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
この例では、もし4つのスタンバイサーバs1
、s2
、s3
、s4
が稼働中なら、トランザクションのコミットは、s1
、s2
、s3
のどれか二つのスタンバイから応答があるまで待たされます。
このリストに名前が載っていないので、s4
は非同期スタンバイです。
pg_stat_replication
ビューを使って、スタンバイサーバの同期状態を見ることができます。
通常、同期レプリケーションは、アプリケーションが満足できる程度に実行されることを確実にするために、注意深くスタンバイサーバを計画し設置しなければなりません。 待機のためにシステムリソースを使用することはありませんが、トランザクションロックは転送が確認されるまで継続して保持されます。 結果として同期レプリケーションを注意せずに使用すると、応答時間が増加する、および競合がより高くなるため、データベースアプリケーションの性能は低下します。
PostgreSQLではアプリケーション開発者がレプリケーション経由で必要とする永続性レベルを指定することができます。 これをシステム全体に対して指定することができますし、特定のユーザ、接続、個々のトランザクションに対してさえ指定することもできます。
例えばアプリケーションの作業量が、重要な顧客詳細の変更が10%、ユーザ間のチャットメッセージなど、あまり重要ではなく、失ったとしても業務をより簡単に戻すことができるようなデータの変更が90% という構成を考えてみます。
(プライマリ上で)アプリケーションレベルで指定する同期レプリケーションオプションを使用して、作業全体を低速化させることなく、最も重要な変更に対して同期レプリケーションを企てることができます。 アプリケーションレベルのオプションは、高い性能が求められるアプリケーションで同期レプリケーションの利点が得られる、重要かつ現実的な手段です。
生成されるWALデータの割合よりネットワーク帯域幅が大きくなければならないことを考慮しなければなりません。
synchronous_commit
が、on
、remote_apply
、remote_write
のいずれかに設定されている場合、synchronous_standby_names
には、コミットされたトランザクションが応答を待つ同期スタンバイの数と名前を指定します。
そのようなトランザクションのコミットは、同期スタンバイのどれかがクラッシュすると決して完了しないかもしれません。
高可用性のもっとも良い解決方法は、想定したのと同じ数の同期スタンバイを確実に確保することです。
これは、synchronous_standby_names
を使って同期スタンバイ候補を複数指定することによって実現できます。
そのリストの最初の方に名前が上がっているスタンバイは、同期スタンバイとして使用されます。
その後の方に名前が上がっているスタンバイは、同期スタンバイのどれかが故障した時に、その役割を取って代わります。
優先度に基づく同期レプリケーションでは、リストの前の方に名前が現れるスタンバイが同期スタンバイになります。 現在の同期スタンバイのどれかが故障した際には、リストの後の方にあるスタンバイが同期スタンバイの役割を引き継ぎます。
クォーラムに基づく同期レプリケーションでは、リストに現れたすべてのスタンバイが同期スタンバイの候補となります。 そのどれかが故障した場合でも、他のスタンバイは引き続き同期スタンバイの候補としての役割を担い続けます。
スタンバイが最初にプライマリに接続された時、それはまだ適切に同期されていません。
これはcatchup
モードと呼ばれます。
一旦スタンバイとプライマリ間の遅延がゼロになると、実時間streaming
状態に移ります。
追従(catchup)期間はスタンバイが作成された直後は長くなるかもしれません。
スタンバイが停止している場合、追従期間はスタンバイの停止期間にしたがって長くなります。
スタンバイは、streaming
状態に達した後でのみ、同期スタンバイになることができます。
この状態は、pg_stat_replication
ビューで見ることができます。
コミットが受領通知を待機している間にプライマリが再起動した場合、プライマリデータベースが復旧した後、待機中のトランザクションは完全にコミットされたものと記録されます。 すべてのスタンバイがプライマリのクラッシュ時点で送信中のWALデータのすべてを受信したかどうかを確認する方法はありません。 トランザクションの一部は、プライマリではコミットされたものと表示されていたとしても、スタンバイではコミットされていないと表示されるかもしれません。 PostgreSQLは、WALデータをすべてのスタンバイが安全に受信したことが分かるまで、アプリケーションは明示的なトランザクションコミットの成功に関する受領通知を受けとらないことを保証しています。
要求していた数の同期スタンバイを本当に確保できないときは、トランザクションが応答を待たなければならない同期スタンバイの数を、synchronous_standby_names
から減らしてください(もしくは無効にします)。
そして、プライマリサーバの設定ファイルを再読み込みしてください。
プライマリが既存のスタンバイサーバから切り離された場合は、スタンバイサーバの中から最善と思われる候補にフェイルオーバーしてください。
トランザクションの待機中にスタンバイサーバを再作成する必要がある場合、pg_start_backup()およびpg_stop_backup()を実行するコマンドをsynchronous_commit
= off
であるセッション内で確実に実行してください。
さもないとこれらの要求はスタンバイに現れるまで永遠に待機します。
スタンバイにおいてWALの継続的アーカイビングが行われる場合、2つのシナリオが考えられます。
WALアーカイブがプライマリとスタンバイで共有されるケースと、スタンバイが自分のWALアーカイブを持つケースです。
スタンバイが自分のWALアーカイブを持つケースでは、archive_mode
をalways
に設定しておくことにより、アーカイブからリストアされたWALセグメントであろうと、ストリーミングレプリケーション由来のWALセグメントであろうと、WALセグメントを受信する度にスタンバイはアーカイブコマンドを呼び出します。
共有アーカイブのケースも同じように扱えますが、archive_command
はアーカイブしようとしているファイルがすでに存在していて、それが同一内容かどうかのチェックを行う必要があります。
このため、archive_command
はより工夫が必要です。
というのも、archive_command
は既存のファイルを異なる内容で置き換えてはいけませんし、またまったく同じ内容のファイルを置き換えた場合には成功したと報告しなければならないからです。
更に、2つのサーバが同時に同じファイルをアーカイブしようとした時に、競合状態が起きないようにしなければなりません。
archive_mode
がon
の場合には、リカバリモードあるいはスタンバイモードではアーカイブは有効になりません。
スタンバイサーバが昇格すると、昇格後にスタンバイサーバはアーカイブを開始します。
しかし、自分が生成しなかったWALやタイムライン履歴ファイルは一切アーカイブしません。
完全な一連のWALファイルをアーカイブから取り出すためには、WALがスタンバイに到着する前に、すべてのWALがアーカイブされていることを保証しなければなりません。
ファイルベースのログシッピングにおいても本質的にはこの通りです。
というのも、スタンバイはアーカイブにあるファイルだけをリストアできるからです。
ストリーミングレプリケーションが有効ならば、この限りではありません。
サーバがリカバリモードでない場合には、on
とalways
のモードの間には違いはありません。