ロジカルデコーディングは、データベースのテーブルへの恒久的な更新を、一貫性があって、データベース内部の状態に関する詳細な知識がなくても容易に理解できる形式として取得するプロセスです。
PostgreSQLにおいてロジカルデコーディングは、記憶装置のレベルで更新を記述する書き込み先行ログの内容を、タプルやSQL文のストリームといったアプリケーション固有の形式にデコードすることによって実装されています。
ロジカルレプリケーションの文脈ではスロットは、元のサーバで行われた変更と同じ順序でクライアント上でリプレイできるようなストリームを表します。 それぞれのスロットは、単一のデータベース上の変更操作の連鎖をストリームとして流します。
またPostgreSQLには、ストリーミングレプリケーションスロットがあります (27.2.5参照)。しかし、ここでの説明とは少し違う使い方がされています。
それぞれのレプリケーションスロットはPostgreSQLクラスタの中で一意な識別子を持っています。 スロットは、そのために使用される接続とは独立しており、クラッシュセーフです。
ロジカルスロットは、通常の操作においては、各々の変更操作を一度だけ送出します。 それぞれのスロットにおける現在位置は、チェックポイントのときにだけ永続的になります。 ですからクラッシュすると、スロットは以前のLSNに戻ってしまうかもしれませんし、サーバの再起動時には最近の変更が再送されることになります。 ロジカルデコーディングのクライアントは、同じメッセージを複数回扱うことによる好ましくない結果を避けることに対して責任を追っています。 クライアントはデコーディングの際に最後に確認したLSNを記録し、繰り返されるデータをスキップしたり、(レプリケーションプロトコルを使う場合に)サーバに開始時点を決めさせるのではなく、記録しておいたLSNからデコーディングを始めるように要求するかもしれません。 レプリケーション進捗追跡機能はこの目的のために設計されています。 replication originsを参照してください。
単一のデータベース中に、お互いに独立した複数のスロットが存在しても構いません。 それぞれのスロットは自分自身の状態を持っており、データベース更新のストリーム上の別の場所から変更データを受信する異なる消費者があり得ます。 多くのアプリケーションにとっては、各消費者に対して個別のスロットが必要となるでしょう。
ロジカルレプリケーションスロットは、受信者の状態については関知しません。 同時にでなければ、同じスロットを使う複数の異なる受信者を持つことさえできます。 その場合は、直近の受信者がストリームの消費を終了した時点から更新データを受信するだけです。 どの時点でも1つのスロットからの変更を消費できるのは1つの受信側だけです。
ロジカルレプリケーションスロットは、ホットスタンバイ上でも作成できます。
システムカタログから必要な行をVACUUM
が削除するのを防ぐためには、スタンバイ上でhot_standby_feedback
を設定する必要があります。
それでも、必要な行が削除されると、スロットは無効になります。
プライマリとスタンバイの間に物理スロットを使用することを強くお勧めします。
そうしないと、hot_standby_feedback
が動作するのは接続が生きている間だけです(たとえばノードの再起動で破壊されます)。
その場合、プライマリはスタンバイ上のロジカルデコーディングが必要とするシステムカタログ行を削除するかもしれません(スタンバイ上のcatalog_xminについては知らないため)。
既存のスタンバイ上のロジカルスロットも、プライマリ上のwal_level
がlogical
よりも小さくなると無効になります。
これはスタンバイがWALストリームでそのような変更を検出したときにすぐに行われます。
これは、遅れているwalsender(もしあれば)に対して、プライマリでのwal_level
パラメータの変更までの一部のWALレコードがデコードされないことを意味します。
ロジカルスロットの作成には、現在実行中のすべてのトランザクションに関する情報が必要です。
プライマリではこの情報は直接利用できますが、スタンバイではこの情報をプライマリから取得する必要があります。
したがって、スロットの作成はプライマリで何らかのアクティビティが発生するのを待つ必要があるかもしれません。
プライマリがアイドル状態の場合、スタンバイ上でのロジカルスロットの作成にはかなりの時間がかかるかもしれません。
これは、プライマリでpg_log_standby_snapshot
関数を呼び出すことで高速化できます。
レプリケーションスロットは、クラッシュをまたがって永続し、消費者の状態については関知しません。
スロットを使う接続がない場合でも、消費者が必要としているリソースが削除されることを防ぎます。
これによりストレージが消費されます。何故ならば、関連するWALもシステムカタログの行も、レプリケーションスロットが必要とする限りVACUUM
によって削除されないからです。
極端な場合、トランザクションIDの周回(25.1.5を参照)を防ぐためのデータベース停止をもたらす可能性があります。
したがって、必要でなくなったスロットは削除すべきです。
出力プラグインは、書き込み先行ログの内部データ表現を、レプリケーションスロットの消費者が必要とする形式に変換します。
ストリーミングレプリケーションのインタフェースを使って新しいスロットを作ると(CREATE_REPLICATION_SLOT参照)、スナップショットがエクスポートされます(9.27.5参照)。
このスナップショットはまさにその時点でのデータベースの状態を示しており、スナップショット以後のすべての変更は更新ストリームに含まれるようになります。
このことを利用して、スロットが作られた際のデータベースの状態をSET TRANSACTION SNAPSHOT
を使って読み込むことにより、新しいレプリカを作ることができます。
このトランザクションは、その時点のデータベースの状態をダンプするために使用することができます。
また、スロットに含まれるデータを使って、ダンプした後で行われた更新を失うことなくデータベースを更新できます。
スナップショットの作成はいつでも可能なわけではありません。
とりわけ、ホットスタンバイに接続するときは失敗します。
スナップショットのエクスポートが必要ないアプリケーションは、NOEXPORT_SNAPSHOT
オプションを使ってスナップショットのエクスポートを抑止できます。