★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 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

26.2. ログシッピングスタンバイサーバ

継続的なアーカイブ処理を使用して、プライマリサーバが失敗した場合に操作を引き継ぐ準備がなされた、1つ以上のスタンバイサーバを持つ高可用性(HA)クラスタ構成を作成することができます。 この機能はウォームスタンバイまたはログシッピングとして広く知られています。

プライマリサーバとスタンバイサーバは、この機能を提供するために共同して稼動しますが、サーバとサーバはゆるく結合しています。 プライマリサーバは継続的アーカイブモードで動作し、各スタンバイサーバはプライマリからWALファイルを読み取る、継続的リカバリモードで動作します。 この機能を可能にするために、データベースのテーブル変更は不要です。 したがって、他のレプリケーションの解法に比べて、管理にかかるオーバーヘッドが減少します。 この構成はプライマリサーバの性能への影響も相対的に減少させます。

あるデータベースサーバから他へ直接WALレコードを移動することは通常、ログシッピングと説明されます。 PostgreSQLはファイルベースのログシッピングを実装します。 つまりWALレコードはある時点で1つのファイル(WALセグメント)として送信されることを意味します。 WALファイル(16MB)は隣り合うシステム、同じサイトの別システム、地球の裏側のシステムなど距離に関わらず、簡単かつ安価に送付することができます。 この技法に必要な帯域幅はプライマリサーバのトランザクションの頻度に応じて変動します。 レコードベースのログシッピングはより粒度を細かくしたもので、ネットワーク接続を介してWALの変更を増分的に流します(26.2.5. ストリーミングレプリケーション参照)。

ログシッピングが非同期であることに注意しなければなりません。 つまり、WALレコードはトランザクションがコミットした後に転送されます。 結果として、プライマリサーバが災害などの致命的な失敗をうけた場合、送信されていないトランザクションが失われますので、データを損失する空白期間があります。 ファイルベースのログシッピングにおけるデータ損失の空白期間量をarchive_timeoutパラメータを用いて制限することができます。 これは数秒程度まで小さく設定することができます。 しかし、低く設定するとファイル転送に必要な帯域幅が増大します。 ストリーミングレプリケーション(26.2.5. ストリーミングレプリケーション参照)により、データを損失する期間を非常に小さくすることができます。

リカバリ処理の性能は十分よく、一度実施されれば、スタンバイサーバが完全な状態から逸脱するのは一時的にしかすぎません。 結果としてこれは、高可用性を提供するウォームスタンバイ構成と呼ばれます。 保管されたベースバックアップからサーバをリストアし、ロールフォワードを行うことはおそらく長時間かかりますので、これは高可用性のための解法とはいえず、災害からのリカバリのための解法です。 スタンバイサーバは読み取り専用の問い合わせに使用することもできます。 この場合ホットスタンバイサーバと呼ばれます。 詳細については26.5. ホットスタンバイを参照してください。

26.2.1. 計画

プライマリサーバとスタンバイサーバを、少なくともデータベースサーバという見地でできる限り同じになるように作成することを通常勧めます。 具体的には、テーブル空間に関連するパス名はそのまま渡されますので、テーブル空間機能を使用する場合には、プライマリとスタンバイサーバの両方でテーブル空間用のマウントパスを同じにしておかなければなりません。 CREATE TABLESPACEをプライマリで実行する場合、そのコマンドを実行する前に必要な新しいマウントポイントをプライマリとすべてのスタンバイサーバで作成しなければならないことに注意してください。 ハードウェアをまったく同じにする必要はありませんが、経験上アプリケーションとシステムの運用期間に渡って2つの同じシステムを管理する方が、異なる2つのシステムを管理するよりも簡単です。 いずれにしてもハードウェアアーキテクチャは必ず同じでなければなりません。 例えば32ビットシステムから64ビットシステムへのシッピングは動作しません。

マイナーリリースの更新ではディスク書式を変更しないというのがPostgreSQLグローバル開発グループの方針ですので、プライマリサーバとスタンバイサーバとの間でマイナーリリースレベルの違いがあってもうまく動作するはずです。 しかし、この場合、公的なサポートは提供されません。 できる限りプライマリサーバとスタンバイサーバとで同じリリースレベルを使用してください。 新しいマイナーリリースに更新する場合、もっとも安全な方針はスタンバイサーバを先に更新することです。 新しいマイナーリリースは以前のマイナーリリースのWALファイルを読み込むことはできますが、逆はできないかもしれません。

26.2.2. スタンバイサーバの動作

スタンバイモードでは、サーバは継続的にマスタサーバから受け取ったWALを適用します。 スタンバイサーバはWALアーカイブ(restore_command参照)から、または直接TCP接続(ストリーミングレプリケーション)を介してマスタサーバから、WALを読み取ることができます。 またスタンバイサーバはスタンバイクラスタのpg_xlogディレクトリにあるすべてのWALをリストアしようと試みます。 これはよくサーバの再起動後、スタンバイが再起動前にマスタから流れ込んだWALを再生する時に発生します。 しかしまたファイルを再生する任意の時点で、手作業でpg_xlogにコピーすることもできます。

起動時、スタンバイサーバはrestore_commandを呼び出して、アーカイブ場所にある利用可能なすべてのWALをリストアすることから始めます。 そこで利用可能なWALの終端に達し、restore_commandが失敗すると、pg_xlogディレクトリにある利用可能な任意のWALのリストアを試みます。 ストリーミングレプリケーションが設定されている場合、これに失敗すると、スタンバイはプライマリサーバへの接続を試み、アーカイブまたはpg_xlog内に存在した最終の有効レコードからWALのストリーミングを開始します。 ストリーミングレプリケーションが未設定時にこれに失敗する場合、または、接続が後で切断される場合、スタンバイは最初に戻り、アーカイブからのファイルのリストアを繰り返し行います。 このアーカイブ、pg_xlog、ストリーミングレプリケーションからという再試行の繰り返しはサーバが停止する、あるいはトリガファイルによるフェールオーバが発行されるまで続きます。

pg_ctl promoteが実行された時またはトリガファイル(trigger_file)が存在する時、スタンバイモードは終了し、サーバは通常の動作に切り替わります。 フェールオーバの前に、アーカイブまたはpg_xlog内の即座に利用可能なWALをすべてリストアします。 しかし、マスタへの接続を行おうとはしません。

26.2.3. スタンバイサーバのためのマスタの準備

25.3. 継続的アーカイブとポイントインタイムリカバリ(PITR)で説明したように、スタンバイからアクセス可能なアーカイブディレクトリに対してプライマリで継続的なアーカイブを設定してください。 このアーカイブ場所はマスタが停止した時であってもスタンバイからアクセス可能でなければなりません。 つまり、マスタサーバ上ではなく、スタンバイサーバ自身上に存在するか、または他の高信頼性サーバ上に存在しなければなりません。

ストリーミングレプリケーションを使用したい場合、スタンバイサーバ(複数可)からのレプリケーション接続を受け付けるようにプライマリサーバで認証を設定してください。 つまり、ロールを作成し適切な項目を提供、あるいは、そのデータベースフィールドとしてreplicationを持つ項目をpg_hba.conf内に設定してください。 また、プライマリサーバの設定ファイルにおいてmax_wal_sendersが十分大きな値に設定されていることを確認してください。 レプリケーションスロットを使用している場合は、max_replication_slotsも十分に設定されているか確認してください。

25.3.2. ベースバックアップの作成に記述したように、スタンバイサーバの再起動のために、ベースバックアップを取得してください。

26.2.4. スタンバイサーバの設定

スタンバイサーバを設定するためには、プライマリサーバから取得したベースバックアップをリストアしてください(25.3.4. 継続的アーカイブによるバックアップを使用した復旧参照)。 スタンバイのクラスタデータディレクトリ内にrecovery.confリカバリコマンドファイルを作成し、standby_modeを有効にしてください。 WALアーカイブからファイルをコピーする簡単なコマンドをrestore_commandに設定してください。 高可用性のために複数のスタンバイサーバを持たせようとしている場合、recovery_target_timelinelatestに設定し、スタンバイサーバが他のスタンバイにフェールオーバする時に発生するタイムラインの変更に従うようにします。

注記

ここで説明した組み込みのスタンバイモードといっしょに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と共に使用されるように設計されています。 しかし、バックアップを目的にアーカイブを使用している場合には、スタンバイから必要とされなくなったファイルであっても、最新のベースバックアップの時点からリカバリするために必要なファイルを保持しなければならないことに注意してください。

recovery.confの簡単な例を以下に示します。

standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
restore_command = 'cp /path/to/archive/%f %p'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'

スタンバイサーバの台数に制限はありませんが、ストリーミングレプリケーションを使用するなら、プライマリサーバに同時に接続できるようにmax_wal_sendersを十分な数に設定してください。

26.2.5. ストリーミングレプリケーション

ストリーミングレプリケーションによりスタンバイサーバはファイルベースのログシッピングよりもより最近の状態を維持できるようになります。 スタンバイは、WALレコードが生成された時にWALファイルがいっぱいになるまで待機せずにWALレコードをスタンバイに流し出すプライマリと接続します。

ストリーミングレプリケーションはデフォルトで非同期で、(26.2.8. 同期レプリケーション参照) この場合、プライマリでトランザクションがコミットされてから、その変更がスタンバイ側で参照可能になるまでの間にわずかな遅延がまだあります。 しかし、この遅延はファイルベースのログシッピングよりも非常に小さなもので、負荷に追随できる程度の能力があるスタンバイであれば通常は1秒以下です。 ストリーミングレプリケーションでは、データ損失期間を減らすためのarchive_timeoutを必要としません。

ファイルベースの継続的アーカイブのないストリーミングレプリケーションを使用している場合、スタンバイが受け取る前に古いWALセグメントを再利用するかもしれません。 もし、そうなった場合はスタンバイは新しいベースバックアップから再作成しなければならなくなります。 wal_keep_segmentsを十分に大きくしたり、レプリケーションスロットにスタンバイを設定することでWALセグメントがすぐに再利用されることを防ぎ、これを防ぐことができます。WALアーカイブをスタンバイからアクセスできる位置に設定する場合は、スタンバイが常にWALセグメントを追随することができるため、これらの解決策は要求されません。

ストリーミングレプリケーションを使用するためには、26.2. ログシッピングスタンバイサーバの説明のようにファイルベースのログシッピングを行うスタンバイサーバを設定してください。 ファイルベースのログシッピングを行うスタンバイをストリーミングレプリケーションを行うスタンバイに切り替える手順は、recovery.conf内のprimary_conninfo設定をプライマリサーバを指し示すように設定することです。 スタンバイサーバがプライマリサーバ上のreplication疑似データベースに接続できる(26.2.5.1. 認証参照)ように、プライマリでlisten_addressesと認証オプション(pg_hba.conf参照)を設定してください。

キープアライブソケットオプションをサポートするシステムでは、tcp_keepalives_idletcp_keepalives_intervalおよびtcp_keepalives_countを設定することで、プライマリの接続切断の即時検知に有用です。

スタンバイサーバからの同時接続数の最大値を設定してください(詳細はmax_wal_sendersを参照)。

スタンバイが起動し、primary_conninfoが正しく設定されると、スタンバイはアーカイブ内で利用可能なWALファイルをすべて再生した後にプライマリと接続します。 接続の確立に成功すると、スタンバイでWAL受信プロセスが存在し、プライマリで対応するWAL送信プロセスが存在します。

26.2.5.1. 認証

信頼できるユーザのみが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

プライマリサーバのホスト名とポート番号、接続する利用者名およびパスワードは、recovery.confファイルで指定します。 パスワードはスタンバイサーバの~/.pgpassファイルでも設定できます(databaseフィールドのreplicationを指定します)。 例えば、プライマリサーバが稼動するホストの IP アドレスが192.168.1.50でポート番号が5432であり、レプリケーションのアカウント名がfooであり、パスワードがfoopassである場合、管理者はスタンバイサーバのrecovery.confファイルに次行を追加できます。

# プライマリサーバが 192.168.1.50 のホストの 5432ポートで稼動し
# 利用者名が foo でパスワードが foopass とする
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'

26.2.5.2. 監視

ストリーミングレプリケーションの重要な健全性尺度は、プライマリサーバで生成されたがスタンバイサーバではまだ適用されていないWALレコードの量です。 プライマリサーバの現在のWAL書き込み位置とスタンバイサーバの受理したWALの最終位置を比較すれば、この遅延を計算できます。 これらの位置は、プライマリサーバではpg_current_xlog_locationを、スタンバイサーバではpg_last_xlog_receive_locationを使用すれば検索できます(詳細は表9.78「バックアップ制御関数」および表9.79「リカバリ情報関数」を参照)。 スタンバイサーバの最終位置は、psコマンドを使用して WAL受信プロセスの状態としても表示できます(詳細は28.1. 標準的なUnixツールを参照)。

pg_stat_replicationビューを介してWAL送信処理プロセスのリストを入手することができます。 pg_current_xlog_locationsent_locationフィールドとの違いが大きい場合、マスタサーバが高負荷状態であることを示している可能性があります。 一方でスタンバイサーバ上のsent_locationpg_last_xlog_receive_locationの値の差異は、ネットワーク遅延、またはスタンバイが高負荷状態であることを示す可能性があります。

26.2.6. レプリケーションスロット

レプリケーションスロットはマスターが全てのスタンバイがWALセグメントを受け取るまで削除を防止したり、たとえ、スタンバイが接続していなくとも、マスターが行を削除してしまうリカバリの競合を自動的に防ぐ機能を提供します。

レプリケーションスロットを使用しない場合、古いWALセグメントの削除を防ぐためには、wal_keep_segmentsを使用するか、アーカイブarchive_commandを使用します。 しかし、これらの方法は要求される以上のWALを残すことに対し、レプリケーションスロットは必要と判断されたWALのみを残します。 これらの方法のメリットはpg_xlogが要求する領域を抑制することです。現時点でレプリケーションスロットを使用する他の目的はありません。

同様に、hot_standby_feedbackvacuum_defer_cleanup_ageはまだ使用する行がvacuumにより削除されることを防ぐ機能を提供しますが、スタンバイが接続されていない時間の行は保護出来ず、十分に保護するために高い値を設定することがしばしばあります。レプリケーションスロットにはこのような短所がありません。

26.2.6.1. レプリケーションスロットへの問い合わせと操作

いずれのレプリケーションスロットにも小文字、数字、アンダースコアを含む名前があります。

レプリケーションスロットとその状態はpg_replication_slots ビューより確認できます。

レプリケーションスロットはストリーミングレプリケーションプロトコル( 51.3. ストリーミングレプリケーションプロトコル参照)もしくはSQLファンクション(9.26.6. レプリケーション関数参照)を使用し、作成や削除ができます。

26.2.6.2. 設定の例

以下のような方法でレプリケーションスロットを作成できます。

postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
  slot_name  | xlog_position
-------------+---------------
 node_a_slot |

postgres=# SELECT * FROM pg_replication_slots;
  slot_name  | slot_type | datoid | database | active | xmin | restart_lsn | confirmed_flush_lsn
-------------+-----------+--------+----------+--------+------+-------------+---------------------
 node_a_slot | physical  |        |          | f      |      |             |
(1 row)

スタンバイのレプリケーションスロットを使用できるように設定するためには、primary_slot_nameをスタンバイ側のrecovery.confに設定します。 以下は設定例です。:

standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
primary_slot_name = 'node_a_slot'

26.2.7. カスケードレプリケーション

カスケードレプリケーションは、リレーのような振る舞い、つまり、スタンバイサーバから他のスタンバイにレプリケーション接続し、WALレコードを送信することができます。 マスターサーバへ直接の接続を減らしたり、サイト相互の帯域オーバヘッドを最小化するために使用することができます。

カスケードスタンバイとして知られているとおり、スタンバイは受け取り手としても送り手としても振る舞うことができます。 よりマスターサーバに近いスタンバイサーバは上流サーバと呼ばれるのに対し、より遠いスタンバイサーバは下流サーバと呼ばれます。 カスケードレプリケーションには下流サーバの数に制限は設定されていません。しかし、どのスタンバイサーバも最終的には1つのマスター/プライマリサーバに繋がる1つの上流サーバに接続します。

カスケードスタンバイはマスターから受け取ったWALレコードだけでなく、アーカイブからリストアしたWALアーカイブも送信します。 このため、レプリケーション接続が上流サーバで切断しても、ストリーミングレプリケーションは下流サーバへ新しいWAL レコードがある限り継続します。

カスケードレプリケーションは現時点では非同期です。同期レプリケーション(参照26.2.8. 同期レプリケーション)の設定は現時点でカスケードレプリケーションへは影響を与えません。

ホットスタンバイがどの様に配置されていても、ホットスタンバイフィードバックは上流に伝播します。

上流スタンバイサーバが昇格し、新しいマスターサーバになった場合、recovery_target_timeline'latest'に設定されていれば、下流サーバは新マスターサーバからのストリーミングレプリケーションを継続します。

カスケードレプリケーションを使うためには、カスケードスタンバイをセットアップ、つまり、レプリケーション接続を許可してください。(max_wal_sendershot_standbyおよび、 クライアント認証を設定してください) また、下流スタンバイがカスケードスタンバイに接続できるために、下流スタンバイではprimary_conninfoを設定する必要があります。

26.2.8. 同期レプリケーション

PostgreSQLのストリーミングレプリケーションはデフォルトで非同期です。 プライマリサーバがクラッシュした場合、コミットされた一部のトランザクションがスタンバイサーバに複製されず、データ損失を引き起こす可能性があります。 データ損失量はフェールオーバ時点のレプリケーション遅延に比例します。

同期レプリケーションは、あるトランザクションでなされた変更はすべて、1つ以上の同期スタンバイサーバに転送されていることを確実にする機能を提供します。 これはトランザクションコミットで提供される永続性の標準レベルを拡張します。 この保護レベルはコンピュータ科学理論では、2-safeレプリケーション、そしてsynchronous_commitremote_writeに設定されている場合にはgroup-1-safe (group-safeと1-safe) と呼ばれます。

同期レプリケーションを要求する時、書き込みトランザクションのコミットはそれぞれ、そのコミットがプライマリサーバおよびスタンバイサーバの両方で、ディスク上のトランザクションログに書き込まれたという確認を受けとるまで待機します。 データ損失が起こる可能性は、プライマリサーバとスタンバイサーバが同時にクラッシュしてしまった場合のみです。 これは非常に高い永続性を提供することができますが、それはシステム管理者が2つのサーバの設置と管理に関して注意を払っている場合のみです。 確認のための待機は、サーバがクラッシュした場合でも変更が失われないということでユーザからの信頼性が大きくなりますが、同時に要求するトランザクションの応答時間も必ず大きくなります。 最小待機時間はプライマリとスタンバイの間の往復遅延時間です。

読み取り専用のトランザクションおよびトランザクションのロールバックはスタンバイサーバからの応答を待つ必要はありません。 副トランザクションのコミットもスタンバイサーバからの応答を待つことはなく、最上位レベルのコミットのみ待機します。 データロード処理やインデックス構築など長時間実行される操作は、最終コミットメッセージまで待機しません。 準備およびコミットの両方を含め、二相コミット動作はすべてコミット待機を必要とします。

26.2.8.1. 基本設定

一度、ストリーミングレプリケーションが設定されている場合、同期レプリケーションの設定には必要な追加設定は1つだけ:synchronous_standby_namesを空でない値に設定することです。 またsynchronous_commitonに設定されていなければなりませんが、これはデフォルト値ですので、通常は変更する必要はありません。(19.5.1. 諸設定 および19.6.2. マスターサーバを参照してください) この設定によりスタンバイがそのコミットレコードを信頼できるストレージに書き込んだことが確認できるまで、各コミットが待たされるようになります。 synchronous_commitは個々のユーザによって設定することができます。 このため、トランザクション単位を基準とした永続性の保証を制御するために、設定ファイルの中で特定のユーザまたはデータベースについて設定することも、アプリケーションによって動的に設定することもできます。

コミットレコードがプライマリ上のディスクに書き出された後、WALレコードがスタンバイに送信されます。 スタンバイにてwal_receiver_status_intervalがゼロに設定されていない限り、スタンバイは新しいWALデータの塊がディスクに書き出される度に応答メッセージを返します。 synchronous_commitremote_applyに設定されている場合には、コミットレコードが再生され、そのトランザクションが可視化されたときに応答メッセージを返します。 スタンバイが、プライマリ上の優先順リストであるsynchronous_standby_namesから同期スタンバイとして選ばれた時は、いつコミットレコードの受領を確認ために待機しているトランザクションを解放すべきかを決めるために、他の同期スタンバイとともにそれらスタンバイからの応答メッセージが考慮されます。 これらのパラメータにより、管理者はどのスタンバイサーバを同期スタンバイとすべきかを指定することができます。 同期レプリケーションの設定は主にマスタでなされることに注意してください。 指名されたスタンバイは直接マスターサーバに接続される必要があります。 つまり、カスケードレプリケーションを使用している下流スタンバイサーバについて、マスターサーバは何も知りません。

synchronous_commitremote_writeに設定することで、個々のコミットは、スタンバイサーバがコミットされたレコードを受け取り、オペレーティングシステムに書きだしたことが確認できるまで待ちますが、スタンバイ上のディスクに吐き出すまでは待ちません。 これは、onと設定するより、提供される永続性は弱くなります。 具体的には、スタンバイサーバはオペレーティングシステムがクラッシュした場合にデータを失う可能性がありますが、PostgreSQLがクラッシュした場合にはデータを失いません。 しかし、実用的にはこの設定はトランザクションの応答時間を短くすることができるので有用です。 データの損失は、プライマリサーバとスタンバイサーバが同時にクラッシュし、かつ、プライマリのデータベースが同時に壊れた場合にのみ発生します。

synchronous_commitremote_applyに設定することで、現在の同期スタンバイがトランザクションを再生し、ユーザから見えるようにしたと報告するまでは各々のコミットは待たされます。 単純なケースでは、因果一貫性を保つ負荷分散を可能にします。

高速シャットダウンが要求された場合、ユーザは待ち状態ではなくなります。 しかし非同期レプリケーションを使用している時と同じく、送信中のWALレコードが現在接続しているスタンバイサーバに転送されるまで、サーバは完全に停止しません。

26.2.8.2. 複数の同期スタンバイ

同期レプリケーションは、一つ以上の同期スタンバイサーバをサポートします。 同期と見なされるすべてのスタンバイサーバがデータの受領を確認するまで、トランザクションは待機します。 トランザクションが応答を待たなければならない同期スタンバイの数は、synchronous_standby_namesで指定されます。 また、このパラメータには、スタンバイの名前のリストを指定します。 このリストは、同期スタンバイとして選ばれる個々のスタンバイの優先順位を決定します。 リストの最初の方に名前が現れるスタンバイには高い優先順位が与えられ、同期と見なされます。 リストの後の方に現れる他のスタンバイサーバは、潜在的な同期スタンバイであることを表します。 何かの理由で現在の同期スタンバイのどれかが切断されると、直ちに次に優先順位の高いスタンバイが取って代わります。

複数同期スタンバイのsynchronous_standby_namesの例を示します。

synchronous_standby_names = '2 (s1, s2, s3)'

この例では、もし4つのスタンバイサーバs1s2s3s4が稼働中なら、s1s2が同期スタンバイに選ばれます。 それらの名前がスタンバイ名のリストの最初の方にあるからです。 s3は潜在的な同期スタンバイで、s1あるいはs2が故障した時に同期スタンバイの役割を取って代わります。 このリストに名前が載っていないので、s4は非同期スタンバイです。

26.2.8.3. 性能に関する考慮

通常、同期レプリケーションは、アプリケーションが満足できる程度に実行されることを確実にするために、注意深くスタンバイサーバを計画し設置しなければなりません。 待機のためにシステムリソースを使用することはありませんが、トランザクションロックは転送が確認されるまで継続して保持されます。 結果として同期レプリケーションを注意せずに使用すると、応答時間が増加する、および競合がより高くなるため、データベースアプリケーションの性能は低下します。

PostgreSQLではアプリケーション開発者がレプリケーション経由で必要とする永続性レベルを指定することができます。 これをシステム全体に対して指定することができますし、特定のユーザ、接続、個々のトランザクションに対してさえ指定することもできます。

例えばアプリケーションの作業量が、重要な顧客詳細の変更が10%、ユーザ間のチャットメッセージなど、あまり重要ではなく、失ったとしても業務をより簡単に戻すことができるようなデータの変更が90% という構成を考えてみます。

(プライマリ上で)アプリケーションレベルで指定する同期レプリケーションオプションを使用して、作業全体を低速化させることなく、最も重要な変更に対して同期レプリケーションを企てることができます。 アプリケーションレベルのオプションは、高い性能が求められるアプリケーションで同期レプリケーションの利点が得られる、重要かつ現実的な手段です。

生成されるWALデータの割合よりネットワーク帯域幅が大きくなければならないことを考慮しなければなりません。

26.2.8.4. 高可用性に関する検討

synchronous_commitが、onremote_applyremote_writeのいずれかに設定されている場合、synchronous_standby_namesには、コミットされたトランザクションが応答を待つ同期スタンバイの数と名前を指定します。 そのようなトランザクションのコミットは、同期スタンバイのどれかがクラッシュすると決して完了しないかもしれません。

高可用性のもっとも良い解決方法は、想定したのと同じ数の同期スタンバイを確実に確保することです。 これは、synchronous_standby_namesを使って同期スタンバイ候補を複数指定することによって実現できます。 そのリストの最初の方に名前が上がっているスタンバイは、同期スタンバイとして使用されます。 その後の方に名前が上がっているスタンバイは、同期スタンバイのどれかが故障した時に、その役割を取って代わります。

スタンバイが最初にプライマリに接続された時、それはまだ適切に同期されていません。 これはcatchupモードと呼ばれます。 一旦スタンバイとプライマリ間の遅延がゼロになると、実時間streaming状態に移ります。 追従(catchup)期間はスタンバイが作成された直後は長くなるかもしれません。 スタンバイが停止している場合、追従期間はスタンバイの停止期間にしたがって長くなります。 スタンバイは、streaming状態に達した後でのみ、同期スタンバイになることができます。

コミットが受領通知を待機している間にプライマリが再起動した場合、プライマリデータベースが復旧した後、待機中のトランザクションは完全にコミットされたものと記録されます。 すべてのスタンバイがプライマリのクラッシュ時点で送信中のWALデータのすべてを受信したかどうかを確認する方法はありません。 トランザクションの一部は、プライマリではコミットされたものと表示されていたとしても、スタンバイではコミットされていないと表示されるかもしれません。 PostgreSQLは、WALデータをすべてのスタンバイが安全に受信したことが分かるまで、アプリケーションは明示的なトランザクションコミットの成功に関する受領通知を受けとらないことを保証しています。

要求していた数の同期スタンバイを本当に確保できないときは、トランザクションが応答を待たなければならない同期スタンバイの数を、synchronous_standby_namesから減らしてください(もしくは無効にします)。 そして、プライマリサーバの設定ファイルを再読み込みしてください。

プライマリが既存のスタンバイサーバから切り離された場合は、スタンバイサーバの中から最善と思われる候補にフェールオーバしてください。

トランザクションの待機中にスタンバイサーバを再作成する必要がある場合、pg_start_backup()およびpg_stop_backup()を実行するコマンドをsynchronous_commit = offであるセッション内で確実に実行してください。 さもないとこれらの要求はスタンバイに現れるまで永遠に待機します。

26.2.9. スタンバイにおける継続的アーカイビング

スタンバイにおいてWALの継続的アーカイビングが行われる場合、2つのシナリオが考えられます。 WALアーカイブがプライマリとスタンバイで共有されるケースと、スタンバイが自分のWALアーカイブを持つケースです。 スタンバイが自分のWALアーカイブを持つケースでは、archive_modealwaysに設定しておくことにより、アーカイブからリストアされたWALセグメントであろうと、ストリーミングレプリケーション由来のWALセグメントであろうと、WALセグメントを受信する度にスタンバイはアーカイブコマンドを呼び出します。 共有アーカイブのケースも同じように扱えますが、archive_commandはアーカイブしようとしているファイルがすでに存在していて、それが同一内容かどうかのチェックを行う必要があります。 このため、archive_commandはより工夫が必要です。 というのも、archive_commandは既存のファイルを異なる内容で置き換えてはいけませんし、またまったく同じ内容のファイルを置き換えた場合には成功したと報告しなければならないからです。 更に、2つのサーバが同時に同じファイルをアーカイブしようとした時に、競合状態が起きないようにしなければなりません。

archive_modeonの場合には、リカバリモードあるいはスタンバイモードではアーカイブは有効になりません。 スタンバイサーバが昇格すると、昇格後にスタンバイサーバはアーカイブを開始します。 しかし、自分が生成しなかったWALは一切アーカイブしません。 完全な一連のWALファイルをアーカイブから取り出すためには、WALがスタンバイに到着する前に、すべてのWALがアーカイブされていることを保証しなければなりません。 ファイルベースのログシッピングにおいても本質的にはこの通りです。 というのも、スタンバイはアーカイブにあるファイルだけをリストアできるからです。 ストリーミングレプリケーションが有効ならば、この限りではありません。 サーバがリカバリモーでない場合には、onalwaysのモードの間には違いはありません。