Azure Database for PostgreSQL フレキシブル サーバーでの論理レプリケーションと論理デコード

Azure Database for PostgreSQL フレキシブル サーバーでは、次の論理データの抽出とレプリケーションの手法がサポートされています:

  1. 論理レプリケーション

    1. データ オブジェクトをレプリケートする、PostgreSQL のネイティブ論理レプリケーションを使用する。 論理レプリケーションを使用すると、テーブル レベルのデータ レプリケーションなど、データ レプリケーションをきめ細かく制御できます。
    2. 論理ストリーミング レプリケーションと、データベースの初期スキーマのコピー、TRUNCATE のサポート、DDL のレプリケート機能などのその他の機能を提供する pglogical 拡張機能を使用します。
  2. 先書きログ (WAL) の内容をデコードすることによって実装される論理デコード

論理レプリケーションと論理デコードを比較する

論理レプリケーションと論理デコードには、似ている点がいくつかあります。 両方とも:

2 つのテクノロジには次のような違いがあります。

論理レプリケーション:

  • レプリケートするテーブルまたはテーブルのセットを指定できます。

論理デコード:

  • データベース内のすべてのテーブルから変更を抽出します。

論理レプリケーションと論理デコードの前提条件

  1. ポータルのパラメーター ページに移動します。

  2. パラメーター wal_levellogical に設定します。

  3. pglogical 拡張機能を使用する場合は、 shared_preload_librariesazure.extensions パラメーターを検索し、ドロップダウン リスト ボックスから pglogical を選択します。

  4. max_worker_processes パラメーターの値を 16 以上に更新します。 そうしないと、 WARNING: out of background worker slotsなどの問題が発生する可能性があります。

  5. 変更を保存し、サーバーを再起動して変更を適用します。

  6. Azure Database for PostgreSQLフレキシブル サーバーで、接続しているリソースからのネットワーク トラフィックが許可されていることを確認します。

  7. 管理者ユーザーのレプリケーションのアクセス許可を付与します。

    ALTER ROLE <adminname> WITH REPLICATION;
    
  8. 使用しているロールに、レプリケートするスキーマに対する 権限 があることを確認します。 そうしないと、 Permission denied for schemaなどのエラーが発生する可能性があります。

レプリケーション ユーザーを通常の管理者アカウントから分離することをお勧めします。

論理レプリケーションと論理デコードを使用する

ネイティブ論理レプリケーションを使用することは、Azure Database for PostgreSQLフレキシブル サーバーからデータをレプリケートする最も簡単な方法です。 SQL インターフェイスまたはストリーミング プロトコルを使用して、変更を使用できます。 SQL インターフェイスを使用して、論理デコードを使用して変更を使用することもできます。

ネイティブ論理レプリケーション

論理レプリケーションでは、 パブリッシャー とサブスクライバーという用語が使用 されます

  • パブリッシャーは、データを送信するAzure Database for PostgreSQLフレキシブル サーバー データベースです。
  • サブスクライバーは、データを受信するAzure Database for PostgreSQLフレキシブル サーバー データベースです。

論理レプリケーションを試すために使用できるサンプル コードを次に示します。

  1. パブリッシャー データベースに接続します。 テーブルを作成し、データをいくつか追加します。

    CREATE TABLE basic (id INTEGER NOT NULL PRIMARY KEY, a TEXT);
    INSERT INTO basic VALUES (1, 'apple');
    INSERT INTO basic VALUES (2, 'banana');
    
  2. テーブルのパブリケーションを作成します。

    CREATE PUBLICATION pub FOR TABLE basic;
    
  3. サブスクライバー データベースに接続します。 パブリッシャーと同じスキーマでテーブルを作成します。

    CREATE TABLE basic (id INTEGER NOT NULL PRIMARY KEY, a TEXT);
    
  4. 前に作成したパブリケーションに接続するサブスクリプションを作成します。

    CREATE SUBSCRIPTION sub CONNECTION 'host=<server>.postgres.database.azure.com user=<rep_user> dbname=<dbname> password=<password>' PUBLICATION pub;
    
  5. これで、サブスクライバーのテーブルに対してクエリを実行できるようになります。 パブリッシャーからデータを受信していることがわかります。

    SELECT * FROM basic;
    

    パブリッシャーのテーブルに行を追加し、サブスクライバーで変更を表示することができます。

    データが表示されない場合は、 azure_pg_admin ロールのメンバーであるユーザーに切り替えて、テーブルの内容を確認します。

論理レプリケーションの詳細については、PostgreSQL のドキュメントを参照してください。

同じサーバー上のデータベース間で論理レプリケーションを使用する

同じAzure Database for PostgreSQLフレキシブル サーバー上の異なるデータベース間で論理レプリケーションを設定するには、実装の制限を回避するための特定のガイドラインに従ってください。 現時点では、レプリケーション スロットが同じコマンド内に作成されていない場合にのみ、同じデータベース クラスターに接続するサブスクリプションを作成できます。 それ以外の場合、 CREATE SUBSCRIPTION 呼び出しは、 LibPQWalReceiverReceive 待機イベントでハングします。 この動作は、Postgres エンジン内の既存の制限が原因であり、今後のリリースで削除される可能性があります。

この制限を回避しながら、同じサーバー上の "ソース" データベースと "ターゲット" データベースの間で論理レプリケーションを設定するには、次の手順に従います。

最初に、ソース データベースとターゲット データベースの両方で同じスキーマを持つ basic という名前のテーブルを作成します。

-- Run this on both source and target databases
CREATE TABLE basic (id INTEGER NOT NULL PRIMARY KEY, a TEXT);

次に、ソース データベースで、テーブルのパブリケーションを作成し、 pg_create_logical_replication_slot 関数を使用して論理レプリケーション スロットを個別に作成します。 この方法は、通常、サブスクリプションと同じコマンドでスロットが作成されるときに発生するハング問題を防ぐのに役立ちます。 pgoutput プラグインを使用します。

-- Run this on the source database
CREATE PUBLICATION pub FOR TABLE basic;
SELECT pg_create_logical_replication_slot('myslot', 'pgoutput');

次に、ターゲット データベースで、以前に作成したパブリケーションのサブスクリプションを作成します。 create_slotfalse に設定して、Azure Database for PostgreSQLフレキシブル サーバーが新しいスロットを作成できないようにし、前の手順で作成したスロット名を指定します。 コマンドを実行する前に、接続文字列のプレースホルダーを実際のデータベース資格情報に置き換えます。

-- Run this on the target database
CREATE SUBSCRIPTION sub
   CONNECTION 'dbname=<source dbname> host=<server>.postgres.database.azure.com port=5432 user=<rep_user> password=<password>'
   PUBLICATION pub
   WITH (create_slot = false, slot_name='myslot');

論理レプリケーションを設定したら、ソース データベースの basic テーブルに新しいレコードを挿入し、ターゲット データベースにレプリケートされることを確認して、それをテストします。

-- Run this on the source database
INSERT INTO basic SELECT 3, 'mango';

-- Run this on the target database
TABLE basic;

すべてが正しく構成されている場合は、ターゲット データベースのソース データベースの新しいレコードが表示され、論理レプリケーションの正常なセットアップが確認されます。

pglogical 拡張機能

プロバイダー データベース サーバーとサブスクライバーで pglogical を構成する例を次に示します。 詳細については、 pglogical 拡張機能のドキュメントを参照してください。 また、前に示した前提条件のタスクを完了してください。

  1. プロバイダーとサブスクライバー データベース サーバーの両方のデータベースに pglogical 拡張機能をインストールします。

    \c myDB
    CREATE EXTENSION pglogical;
    
  2. レプリケーション ユーザーがサーバー管理ユーザー (サーバーを作成したユーザー) でない場合は、 azure_pg_admin ロールのユーザー メンバーシップを付与し、REPLICATION 属性と LOGIN 属性をユーザーに割り当てます。 詳しくは、pglogical のドキュメントをご覧ください。

    GRANT azure_pg_admin to myUser;
    ALTER ROLE myUser REPLICATION LOGIN;
    
  3. プロバイダー (ソースとパブリッシャー) のデータベース サーバーで、プロバイダー ノードを作成します。

    select pglogical.create_node( node_name := 'provider1',
    dsn := ' host=myProviderServer.postgres.database.azure.com port=5432 dbname=myDB user=myUser password=<password>');
    
  4. レプリケーション セットを作成します。

    select pglogical.create_replication_set('myreplicationset');
    
  5. データベース内のすべてのテーブルをレプリケーション セットに追加します。

    SELECT pglogical.replication_set_add_all_tables('myreplicationset', '{public}'::text[]);
    

    別の方法として、特定のスキーマ (testUser など) から既定のレプリケーション セットにテーブルを追加することもできます。

    SELECT pglogical.replication_set_add_all_tables('default', ARRAY['testUser']);
    
  6. サブスクライバーのデータベース サーバーで、サブスクライバー ノードを作成します。

    select pglogical.create_node( node_name := 'subscriber1',
    dsn := ' host=mySubscriberServer.postgres.database.azure.com port=5432 dbname=myDB user=myUser password=<password>' );
    
  7. サブスクリプションを作成して、同期とレプリケーションのプロセスを開始します。

    select pglogical.create_subscription (
    subscription_name := 'subscription1',
    replication_sets := array['myreplicationset'],
    provider_dsn := 'host=myProviderServer.postgres.database.azure.com port=5432 dbname=myDB user=myUser password=<password>');
    
  8. サブスクリプションの状態を確認します。

    SELECT subscription_name, status FROM pglogical.show_subscription_status();
    

注意事項

Pglogical では現在、自動 DDL レプリケーションはサポートされていません。 pg_dump --schema-onlyを使用して、初期スキーマを手動でコピーできます。 pglogical.replicate_ddl_command関数を使用して、プロバイダーとサブスクライバーに対して DDL ステートメントを同時に実行できます。 ここに記載されている、拡張機能のその他の制限事項に注意してください。

論理デコード

ストリーミング プロトコルまたは SQL インターフェイスを介して論理デコードを使用できます。

ストリーミング プロトコル

多くの場合、ストリーミング プロトコルを使用して変更を取り込むほうが適しています。 独自のコンシューマーまたはコネクタを作成することも、 Debezium などのサードパーティのサービスを使用することもできます。

pg_recvlogicalでストリーミング プロトコルを使用する例については、wal2json のドキュメント(pg_recvlogicalでストリーミング プロトコルを使用する例) を参照してください。

SQL インターフェイス

次の例では、wal2json プラグインと共に SQL インターフェイスを使用します。

  1. スロットを作成します。

    SELECT * FROM pg_create_logical_replication_slot('test_slot', 'wal2json');
    
  2. SQL コマンドを実行します。 例えば次が挙げられます。

    CREATE TABLE a_table (
       id varchar(40) NOT NULL,
       item varchar(40),
       PRIMARY KEY (id)
    );
    
    INSERT INTO a_table (id, item) VALUES ('id1', 'item1');
    DELETE FROM a_table WHERE id='id1';
    
  3. 変更を使用します。

    SELECT data FROM pg_logical_slot_get_changes('test_slot', NULL, NULL, 'pretty-print', '1');
    

    出力は次のようになります。

    {
          "change": [
          ]
    }
    {
          "change": [
                   {
                            "kind": "insert",
                            "schema": "public",
                            "table": "a_table",
                            "columnnames": ["id", "item"],
                            "columntypes": ["character varying(40)", "character varying(40)"],
                            "columnvalues": ["id1", "item1"]
                   }
          ]
    }
    {
          "change": [
                   {
                            "kind": "delete",
                            "schema": "public",
                            "table": "a_table",
                            "oldkeys": {
                                  "keynames": ["id"],
                                  "keytypes": ["character varying(40)"],
                                  "keyvalues": ["id1"]
                            }
                   }
          ]
    }
    
  4. スロットの使用が完了したら、スロットを削除します。

    SELECT pg_drop_replication_slot('test_slot');
    

論理デコードの詳細については、PostgreSQL のドキュメント「 論理デコード」を参照してください。

Monitor

論理デコードは監視する必要があります。 未使用のレプリケーション スロットを削除します。 スロットは、変更が読み取られるまで、Postgres の WAL ログと関連するシステムカタログを保持します。 サブスクライバーまたはコンシューマーが失敗した場合、または適切に構成されていない場合は、ログが消費されないまま蓄積され、ストレージがいっぱいになります。 また、未使用のログによって、トランザクション ID の折り返しリスクが増加します。 どちらの状況でも、サーバーを使用できなくなる可能性があります。 そのため、論理レプリケーション スロットを継続的に使用する必要があります。 論理レプリケーション スロットが使用されなくなった場合は、すぐにドロップしてください。

active ビューの pg_replication_slots 列は、コンシューマーがスロットに接続されているかどうかを示します。

SELECT * FROM pg_replication_slots;

[使用されたトランザクション ID の最大数] メトリックと [使用ストレージ] メトリックにアラートを設定して、値が通常のしきい値を超えたときに通知します。

制限事項

  • こちらに記載されているように、論理レプリケーションの制限が適用されます。

  • スロットと HA フェールオーバー - PostgreSQL 16 以前のバージョンでは、Azure Database for PostgreSQLで高可用性 (HA) が有効なサーバーを使用する場合、フェールオーバー イベント中に論理レプリケーション スロットは保持されません。 論理レプリケーション スロットを維持し、フェールオーバー後にデータの整合性を確保するには、PG フェールオーバー スロット拡張機能を使用し、 hot_standby_feedback = onなどのサポート設定を構成します。 この拡張機能を有効にする方法の詳細については、 ドキュメントを参照してください。

論理レプリケーションスロットのフェールオーバー対応

PostgreSQL 17 以降のバージョンでは、スロット同期がネイティブにサポートされています。 適切な PostgreSQL 構成 (sync_replication_slotshot_standby_feedback) を有効にした場合、論理レプリケーション スロットはフェールオーバー後に自動的に保持され、拡張機能は必要ありません。

Important

対応するサブスクライバーが存在しなくなった場合は、プライマリ サーバーの論理レプリケーション スロットを削除する必要があります。 それ以外の場合、WAL ファイルはプライマリに蓄積され、ストレージがいっぱいになります。 ストレージ使用量が 95% に達したとき、または使用可能な容量が 5 GiB 未満の場合、プライマリ サーバーは自動的に読み取り専用モードに切り替わります。 ストレージのしきい値が一定の制限を超え、論理レプリケーション スロットが使用されていない (サブスクライバーが使用できないため) 場合、フレキシブル サーバー Azure Database for PostgreSQL、その未使用の論理レプリケーション スロットが自動的に削除されます。 このアクションにより、蓄積された WAL ファイルが解放され、ストレージがいっぱいになったためにサーバーが使用できなくなる状況を回避できます。