他のバージョンの文書 17 | 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

47.2. ロジカルデコーディングのコンセプト #

47.2.1. ロジカルデコーディング #

ロジカルデコーディングは、データベースのテーブルへの恒久的な更新を、一貫性があって、データベース内部の状態に関する詳細な知識がなくても容易に理解できる形式として取得するプロセスです。

PostgreSQLにおいてロジカルデコーディングは、記憶装置のレベルで更新を記述する先行書き込みログ(WAL)の内容を、タプルやSQL文のストリームといったアプリケーション固有の形式にデコードすることによって実装されています。

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

論理レプリケーションの文脈ではスロットは、元のサーバで行われた変更と同じ順序でクライアント上でリプレイできるようなストリームを表します。 それぞれのスロットは、単一のデータベース上の変更操作の連鎖をストリームとして流します。

注記

またPostgreSQLには、ストリーミングレプリケーションスロットがあります (26.2.5参照)。しかし、ここでの説明とは少し違う使い方がされています。

それぞれのレプリケーションスロットはPostgreSQLクラスタの中で一意な識別子を持っています。 スロットは、そのために使用される接続とは独立しており、クラッシュセーフです。

ロジカルスロットは、通常の操作においては、各々の変更操作を一度だけ送出します。 それぞれのスロットにおける現在位置は、チェックポイントのときにだけ永続的になります。 ですからクラッシュすると、スロットは以前のLSNに戻ってしまうかもしれませんし、サーバの再起動時には最近の変更が再送されることになります。 ロジカルデコーディングのクライアントは、同じメッセージを複数回扱うことによる好ましくない結果を避けることに対して責任を追っています。 クライアントはデコーディングの際に最後に確認したLSNを記録し、繰り返されるデータをスキップしたり、(レプリケーションプロトコルを使う場合に)サーバに開始時点を決めさせるのではなく、記録しておいたLSNからデコーディングを始めるように要求するかもしれません。 レプリケーション進捗追跡機能はこの目的のために設計されています。 replication originsを参照してください。

単一のデータベース中に、お互いに独立した複数のスロットが存在しても構いません。 それぞれのスロットは自分自身の状態を持っており、データベース更新のストリーム上の別の場所から変更データを受信する異なる消費者があり得ます。 多くのアプリケーションにとっては、各消費者に対して個別のスロットが必要となるでしょう。

論理レプリケーションスロットは、受信者の状態については関知しません。 同時にでなければ、同じスロットを使う複数の異なる受信者を持つことさえできます。 その場合は、直近の受信者がストリームの消費を終了した時点から更新データを受信するだけです。 どの時点でも1つのスロットからの変更を消費できるのは1つの受信側だけです。

論理レプリケーションスロットは、ホットスタンバイ上でも作成できます。 システムカタログから必要な行をVACUUMが削除するのを防ぐためには、スタンバイ上でhot_standby_feedbackを設定する必要があります。 それでも、必要な行が削除されると、スロットは無効になります。 プライマリとスタンバイの間に物理スロットを使用することを強くお勧めします。 そうしないと、hot_standby_feedbackが動作するのは接続が生きている間だけです(たとえばノードの再起動で破壊されます)。 その場合、プライマリはスタンバイ上のロジカルデコーディングが必要とするシステムカタログ行を削除するかもしれません(スタンバイ上のcatalog_xminについては知らないため)。 既存のスタンバイ上のロジカルスロットも、プライマリ上のwal_levellogicalよりも小さくなると無効になります。 これはスタンバイがWALストリームでそのような変更を検出したときにすぐに行われます。 これは、遅れているwalsender(もしあれば)に対して、プライマリでのwal_levelパラメータの変更までの一部のWALレコードがデコードされないことを意味します。

ロジカルスロットの作成には、現在実行中のすべてのトランザクションに関する情報が必要です。 プライマリではこの情報は直接利用できますが、スタンバイではこの情報をプライマリから取得する必要があります。 したがって、スロットの作成はプライマリで何らかのアクティビティが発生するのを待つ必要があるかもしれません。 プライマリがアイドル状態の場合、スタンバイ上でのロジカルスロットの作成にはかなりの時間がかかるかもしれません。 これは、プライマリでpg_log_standby_snapshot関数を呼び出すことで高速化できます。

注意

レプリケーションスロットは、クラッシュをまたがって永続し、消費者の状態については関知しません。 スロットを使う接続がない場合でも、消費者が必要としているリソースが削除されることを防ぎます。 これによりストレージが消費されます。何故ならば、関連するWALもシステムカタログの行も、レプリケーションスロットが必要とする限りVACUUMによって削除されないからです。 極端な場合、トランザクションIDの周回(24.1.5を参照)を防ぐためのデータベース停止をもたらす可能性があります。 したがって、必要でなくなったスロットは削除すべきです。

47.2.3. レプリケーションスロットの同期 #

プライマリ上の論理レプリケーションスロットは、ホットスタンバイと同期させることができます。 これは、スロットの作成時にpg_create_logical_replication_slotfailoverパラメータを指定するか、CREATE SUBSCRIPTIONfailoverオプションを指定したうえで、スタンバイでpg_sync_replication_slotsを呼び出すことで可能です。 スタンバイでsync_replication_slotsを設定すると、フェイルオーバースロットをスロット同期ワーカーによって定期的に同期させることができます。 同期を機能させるには、プライマリとスタンバイの間に物理レプリケーションスロットが必要であり(つまり、スタンバイでprimary_slot_nameが設定されている必要があります)、スタンバイではhot_standby_feedbackが有効になっている必要があります。 また、primary_conninfoに有効なdbnameを指定する必要があります。 この物理レプリケーションスロットを、プライマリのsynchronized_standby_slotsリスト内に指定することを強くお勧めします。 これは、サブスクライバーがホットスタンバイよりも早く変更を消費しないようにするためです。 正しく設定されていても、synchronized_standby_slots内に指定されたスロットを待つため、サブスクライバーに変更を送信するときに多少の遅延が予想されます。 synchronized_standby_slotsが使用されている場合、synchronized_standby_slotsで指定された物理レプリケーションスロットに関連付けられた対応するスタンバイが、プライマリサーバ上の最新のフラッシュされた位置までWALを受信することを確認するまで、プライマリサーバは完全にはシャットダウンしません。

フェイルオーバー後に論理レプリケーションを再開できるかどうかは、フェイルオーバー時のスタンバイ上で同期されていたスロットの持つpg_replication_slots.syncedの値によって決まります。 フェイルオーバー前に、スタンバイで同期状態が真となっている永続スロットだけが、フェイルオーバー後の論理レプリケーションに使用できます。 同期されていた一時スロットはロジカルデコーディングには使用できないため、これらのスロットによる論理レプリケーションは再開できません。 例えば、サブスクリプション無効になっているため、同期されたスロットがスタンバイ上で永続化できなかった場合、フェイルオーバー後にサブスクリプションを有効にしても、そのサブスクリプションは再利用できません。

同期されたロジカルスロットからフェイルオーバーの後に論理レプリケーションを再開するには、サブスクリプションの'conninfo'オプションを新しいプライマリサーバを指すように変更する必要があります。 これはALTER SUBSCRIPTION ... CONNECTIONを使用して行います。 スタンバイが昇格する前に先にサブスクリプションを無効にし、接続文字列を変更した後に再度有効にすることをお勧めします。

注意

昇格中に古いプライマリが再度起動する場合があります。 このときサブスクリプションが無効なっていない場合、サブスクライバーは昇格後も接続文字列が変更されるまで、古いプライマリサーバからデータを受信し続ける可能性があります。 これによりデータの不整合の問題が生じ、サブスクライバーが新しいプライマリからのレプリケーションを継続できなくなる可能性があります。

47.2.4. 出力プラグイン #

出力プラグインは、先行書き込みログ(WAL)の内部データ表現を、レプリケーションスロットの消費者が必要とする形式に変換します。

47.2.5. スナップショットのエクスポート #

ストリーミングレプリケーションのインタフェースを使って新しいスロットを作ると(CREATE_REPLICATION_SLOT参照)、スナップショットがエクスポートされます(9.28.5参照)。 このスナップショットはまさにその時点でのデータベースの状態を示しており、スナップショット以後のすべての変更は更新ストリームに含まれるようになります。 このことを利用して、スロットが作られた際のデータベースの状態をSET TRANSACTION SNAPSHOTを使って読み込むことにより、新しいレプリカを作ることができます。 このトランザクションは、その時点のデータベースの状態をダンプするために使用することができます。 また、スロットに含まれるデータを使って、ダンプした後で行われた更新を失うことなくデータベースを更新できます。

スナップショットの作成はいつでも可能なわけではありません。 とりわけ、ホットスタンバイに接続するときは失敗します。 スナップショットのエクスポートが必要ないアプリケーションは、NOEXPORT_SNAPSHOTオプションを使ってスナップショットのエクスポートを抑止できます。