pglogicalを使用したPostgreSQL用のOCIデータベースでの双方向レプリケーション

はじめに

OCI PostgreSQLの論理レプリケーションでは、表のレプリケーション・アイデンティティ(通常は主キー)に基づいて、データ・オブジェクトとその変更をレプリケートできます。パブリッシュ/サブスクライブ・モデルを使用します。このモデルでは、1つ以上のサブスクライバがパブリッシャ・ノードで定義されたパブリケーションをサブスクライブします。サブスクライバはこれらのパブリケーションからデータを取得し、オプションで変更を再公開して、カスケード・レプリケーションまたはより複雑なトポロジを有効にできます。

論理レプリケーションは、論理デコードを使用してWAL (Write-Ahead Log)をデコードすることで、行レベルの変更 (INSERTUPDATE、および DELETE操作)をストリームします。これらのデコードされた変更は、OCI PostgreSQLの物理ストレージ形式に依存せず、論理データ操作のみを表すため、ダウンストリーム・システムの柔軟性が向上します。

このチュートリアルでは、論理レプリケーションにpglogical拡張を使用する方法と、OCI Databaseの2つのデータベース・システム間でPostgreSQLの双方向レプリケーションを有効にする方法について説明します。

双方向複製

双方向レプリケーション(BDR)pglogicalは、2つ以上のOCI PostgreSQLデータベース・システムが互いの変更を公開およびサブスクライブすることを意味します。つまり、各OCI PostgreSQLデータベース・システムは読取りおよび書込みが可能であり、すべての変更は両方向でレプリケートされます。したがって、OCI PostgreSQLデータベース・システムのいずれかに行われた変更もミラー化され、両方に実装されます。

双方向レプリケーションは、通常、複数の場所のユーザーに低レイテンシの読取りおよび書込みアクセスを提供するリージョンまたはグローバル・データベース・アーキテクチャが必要な場合に推奨されます。各リージョンのユーザーの近くで読取り/書込みインスタンスを共存させることで、変更をローカルに行ってから他のリージョンにレプリケートできるため、すべてのノード間でデータが同期されます。

Shows two OCI Database with PostgreSQL instances, with Replication performed in both directions between them.

実際には、ほとんどのユースケースでは、複数のリージョンから書込み可能な表の小規模なサブセットのみが必要ですが、データベースの大部分は単方向レプリケーションを介して読取り専用または一元的に管理できます。

ただし、双方向レプリケーションでは複雑さが発生します。データの整合性を維持し、レプリケーション・トポロジを管理することは、システムの成長に伴って困難になる可能性があります。

アプリケーションの主な目標が、リージョンの停止に対する読取りスケーラビリティおよび自己回復性である場合、よりシンプルで堅牢なアプローチは、同じリージョンまたはリージョン間で、複数の読取りレプリカを持つPostgreSQLインスタンス用の高可用性OCIデータベースをデプロイすることです。

双方向pglogicalの仕組み

pglogicalでは、次のように複数のサブスクリプションおよびパブリケーションを構成できます。

各ノード:

OCI PostgreSQLのリージョン間の単方向pglogicalレプリケーションの詳細は、次のブログを参照してください: リージョン間の単方向pglogical

競合および構成の管理

パブリッシャ(ソース・データベース)は、1つ以上のパブリケーションを定義し、変更データ(DML操作)をサブスクライバ(ターゲット・データベース)に送信します。サブスクライバは、複数のパブリッシャに接続して、その変更をローカル・データベースに適用できます。

pglogical拡張機能は、次のモードをサポートする pglogical.conflict_resolutionパラメータを介して高度な競合解決を提供します。

pglogicalのconflict_resolutionの詳細については、githubの公式ドキュメント「2nd Quadrant Configuration options」を参照してください。

keep_locallast_update_winsまたはfirst_update_winsを使用する場合は、パブリッシャとサブスクライバの両方でtrack_commit_timestampsを有効にする必要があります。この設定を有効にすると、ワークロードに応じて測定可能なパフォーマンスのオーバーヘッドが発生する可能性があることに注意してください。デプロイする前に、本番環境でのパフォーマンスへの影響を評価することを強くお薦めします。

OCI PostgreSQLでの双方向レプリケーションの設定

PostgreSQLのOCIデータベースでpglogical拡張を有効にするには、次のチュートリアルを参照してください: OCI PostgreSQLでpglogical拡張を有効にします

タスク1: 前提条件

PostgreSQLのOCIデータベースにpglogical拡張が作成されたら、データベース・システム#1およびデータベース・システム#2に対して次の権限を付与します。

ALTER ROLE psql WITH REPLICATION;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_replication_origin_session_reset() TO psql; 
GRANT EXECUTE ON FUNCTION pg_catalog.pg_replication_origin_session_setup TO psql; 
GRANT ALL ON FUNCTION pg_catalog.pg_replication_origin_session_setup TO psql;

ノート: psqlは、このチュートリアルのデモンストレーション用に特別に作成されたサンプル・レプリケーション・ユーザーです。

タスク2: 単方向論理レプリケーションの構成

データベース・システム1の場合:

前述の前提条件を完了したら、テスト表を作成し、いくつかのレコードを挿入してpglogicalワークフローを確認します。

CREATE TABLE test_table (
    id serial PRIMARY KEY,
    data text
);
 
INSERT INTO test_table
    (id, data)
VALUES
    (generate_series(1, 1000), 'Test');

プロバイダ・ノードを作成します。

次のステップでは、pglogical関数create_nodeを使用してノードを作成します。

SELECT pglogical.create_node(
    node_name := 'provider1',
    dsn := 'host=primary.xxxxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com
            port=5432
            user=psql
            password=xxxxx
            dbname=postgres'
);

create_nodeファンクションのパラメータ定義を次に示します。

次のステップとして、レプリケーションに含める必要がある表を特定します。pglogicalは、レプリケーション・セットを使用して、レプリケートされる表およびアクション(INSERTUPDATEDELETE)を管理します。create_replication_setファンクションを使用してカスタム・レプリケーション・セットを作成するか、事前定義済のデフォルト・セットを使用して、割り当てられた表に対するすべてのアクションをレプリケートできます。表を含めるには、個々の表に対してreplication_set_add_tableを使用するか、replication_set_add_all_tablesを使用して特定のスキーマからすべての表を追加します。

次のコマンドは、パブリック・スキーマからデフォルトのレプリケーション・セットにすべての表を追加します。

SELECT pglogical.replication_set_add_all_tables(
    'default',
    ARRAY['public']
);

レプリケーションセットについてさらに学習するには、Replication Setsを参照してください。

データベース・システム2の場合:

データベース・システム#1のように一致する表を作成します。

データベース・システム#2で、データベース・システム#1の表の構造と一致するテスト表を作成します。

CREATE TABLE test_table (
    id serial PRIMARY KEY,
    data text
);

サブスクライバ・ノードを作成します。

次に、データベース・システム#1の場合と同様に、pglogical関数create_nodeを使用して、データベース・システム#2にノードを作成します。

SELECT pglogical.create_node(
    node_name := 'subscriber1',
    dsn := 'host=primary.xxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com
            port=5432
            user=psql
            password=xxxxxx
            dbname=postgres'
);

create_nodeファンクションのパラメータ定義を次に示します。

pglogicalサブスクリプションの作成:

次のステップでは、ファンクションcreate_subscriptionを使用してデータベース・システム#1からデータのレプリケーションを開始するサブスクリプションを作成します。

subscription_nameパラメータには、サブスクリプションに任意の名前を指定できます。provider_dsnはデータベース・システム#1の接続文字列で、replication_setsパラメータは使用するレプリケーション・セットを指定します。この例では、デフォルトのレプリケーション・セットを使用しています。

synchronize_data引数は、ソースから既存のデータをコピーするかどうかをpglogicalに指示します。このテストでは、すべての行を将来の変更とともにコピーするため、trueに設定されています。

forward_originsパラメータは、双方向レプリケーションを有効にするために重要です。forward_origins := '{}'を設定すると、ノード自体から発生した変更のみが転送され、他のノードからすでにレプリケートされた変更は転送されません。これにより、レプリケーション・プロセスが無限ループに入るのを防ぎ、変更が連続的に繰り返されます。

SELECT pglogical.create_subscription(
    subscription_name := 'subscription1',
    provider_dsn := 'host=primary.xxxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com
                     port=5432
                     sslmode=require
                     dbname=postgres
                     user=psql
                     password=xxxxx',
    replication_sets := ARRAY['default'],
    synchronize_data := true,
    forward_origins := '{}'
);

購読状況を確認:

次のコマンドを使用して、データベース・システム#2のサブスクリプション・ステータスおよび基本情報を確認します。

select * from pglogical.show_subscription_status();
-[ RECORD 1 ]-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------
subscription_name | subscription1
status            | replicating
provider_node     | provider1
provider_dsn      | host=primary.xxxxxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com port=5432 sslmode=require dbname=postgres user=psql password=xxxxxx
slot_name         | pgl_postgres_provider1_subscription1
replication_sets  | {default}
forward_origins   |

タスク3: データベース・システム#1からデータベース・システム#2へのレプリケーションのテスト

データベース・システム#1(ソース)とデータベース・システム#2(ターゲット)の間にレプリケーションが設定されたので、データベース・システム#1で加えられた変更がデータベース・システム#2に自動的にコピーされるかどうかをテストします。

  1. 初期データの検証

    Database System #2で、表test_tableを確認します。

    postgres=> SELECT COUNT(*) FROM test_table;
     count 
    -------
      1000
    (1 row)
    

    これにより、表にすでに1000行があることが確認されます。

  2. INSERTのテスト

    データベース・システム#1に新しい行を追加します。

    postgres=> INSERT INTO test_table VALUES (10000, 'initial load');
    
  3. データベース・システム#1で確認します。

    postgres=> SELECT * FROM test_table WHERE id = 10000;
      id   |     data     
    -------+--------------
    10000 | initial load
    
  4. Database System #2を確認します。同じ行が表示され、レプリケーションの動作が示されます。

    postgres=> SELECT * FROM test_table WHERE id = 10000;
      id   |     data     
    -------+--------------
    10000 | initial load
    
  5. DELETEのテスト

    データベース・システム#1の同じ行を削除します。

    postgres=> DELETE FROM test_table WHERE id = 10000;
    
  6. 両方のシステムで、行が両方から消えていることを確認します。

    (0 rows)
    
  7. 更新をテストします。

    データベース・システム#1の既存の行を更新します。

    postgres=> UPDATE test_table SET data = 'Initial load' WHERE id = 1;
    

    データベース・システム#1を確認します。

      id   |     data     
    -------+--------------
      1 | Initial load
    

    データベース・システム#2を確認します。更新した値も存在します。

これらのテストでは、INSERTUPDATEおよびDELETE操作が「データベース・システム#1」→「データベース・システム#2」から正しくレプリケートされていることを確認します。

タスク4: 双方向論理レプリケーションの構成

前のタスクでは、データベース・システム#1からデータベース・システム#2への単方向レプリケーションを設定しました。次に、逆方向でのレプリケーションを有効にする追加のコマンドを実行します。

データベース・システム2の場合:

データベース・システム#1の場合と同様に、レプリケーション・セットを設定します。

SELECT pglogical.replication_set_add_all_tables(
    'default',
    ARRAY['public']
);

データベース・システム#1:

データベース・システム#1で、データベース・システム#2からの変更のフェッチを開始するようにサブスクリプションを作成します。

SELECT pglogical.create_subscription(
    subscription_name := 'subscription2',
    provider_dsn := 'host=primary.xxxxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com
                     port=5432
                     sslmode=require
                     dbname=postgres
                     user=psql
                     password=xxxxx',
    replication_sets := ARRAY['default'],
    synchronize_data := false,
    forward_origins := '{}'
);

前のコマンドでは、synchronize_data引数がfalseに設定されています(以前と異なります)。これは、両方の表に同じデータがすでに含まれているため、データベース・システム#2からデータベース・システム#1に既存のデータをコピーする必要がないためです。

このコマンドを使用すると、双方向レプリケーションの設定が完了し、一方のサーバーで加えられた変更がもう一方のサーバーにレプリケートされます。次に、データベース・システム#1のサブスクリプション・ステータスを確認します。

データベース・システム#1のサブスクリプション・ステータスを確認します。

次のコマンドを使用して、Database System #1のサブスクリプション・ステータスおよび基本情報を確認します。

select * from pglogical.show_subscription_status();
-[ RECORD 1 ]-----+----------------------------------------------------------------------------------------------------------------------------------------------------------------
subscription_name | subscription2
status            | replicating
provider_node     | subscriber1
provider_dsn      | host=primary.xxxxxxxx.postgresql.us-phoenix-1.oci.oraclecloud.com port=5432 sslmode=require dbname=postgres user=psql password=xxxxx
slot_name         | pgl_postgres_subscriber1_subscription2
replication_sets  | {default}
forward_origins   |

タスク5: 双方向レプリケーションのテスト

まず、双方向レプリケーションが正しく機能していることを確認するために、両方のデータベース・システムに行を追加します。

  1. データベース・システム#1に行を挿入します。

    データベース・システム#1で次のコマンドを実行します。

    postgres=# INSERT INTO test_table VALUES (1001, 'Initial_load');
    INSERT 0 1
    
  2. データベース・システム#1に挿入された行を確認します。

    postgres=# SELECT * FROM test_table WHERE id = 1001;
      id  |     data     
    ------+--------------
    1001 | Initial_load
    (1 row)
    
  3. データベース・システム#2でレプリケーションを確認します。

    次に、データベース・システム#2で、行がレプリケートされたことを確認します。

    postgres=> SELECT * FROM test_table WHERE id = 1001;
      id  |     data     
    ------+--------------
    1001 | Initial_load
    (1 row)
    

    これは、データベース・システム#1への挿入がデータベース・システム#2にレプリケートされたことを示しています。

  4. データベース・システム#2に行を挿入します。

    データベース・システム#2で次のコマンドを実行します。

    postgres=> INSERT INTO test_table VALUES (1002, 'Initial_load');
    INSERT 0 1
    
  5. データベース・システム#2に挿入された行を確認します。

    postgres=> SELECT * FROM test_table WHERE id = 1002;
      id  |     data     
    ------+--------------
    1002 | Initial_load
    (1 row)
    
  6. データベース・システム#1でレプリケーションを確認します。

    ここで、データベース・システム#1をチェックして、行がレプリケートされたことを確認します。

    postgres=# SELECT * FROM test_table WHERE id = 1002;
      id  |     data     
    ------+--------------
    1002 | Initial_load
    (1 row)
    

    このテストは、データ変更がデータベース・システム#1データベース・システム#2の両方向で正常にレプリケートされたことを確認します。

論理レプリケーション・ラグの監視

pglogicalの設定が完了したら、レプリケーション・ログをモニターして、レプリケーション・スロット、遅延およびその他の関連メトリックを追跡する必要があります。

select * from pg_stat_replication;

このコマンドは、OCI PostgreSQLのレプリケーションの現在のステータスを返します。

まとめ

このチュートリアルでは、pglogicalを使用したPostgreSQL双方向レプリケーションの構成について説明します。双方向レプリケーションにより、データベース・インフラストラクチャが複雑になり、さらに労力がかかるため、ユース・ケースに適合していることを確認することが重要です。アプリケーションで異なるリージョンにまたがる複数のライターが必要で、データベース・シャーディングを実行できない場合は、双方向レプリケーションが理想的なソリューションです。

確認

その他の学習リソース

docs.oracle.com/learnで他のラボを確認するか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスして、Oracle Learning Explorerになります。

製品ドキュメントについては、Oracle Help Centerを参照してください。