pgactive を使用したアクティブ/アクティブレプリケーションのサポート - Amazon Relational Database Service

pgactive を使用したアクティブ/アクティブレプリケーションのサポート

pgactive 拡張は、アクティブ/アクティブレプリケーションを使用して、複数の RDS for PostgreSQL データベースに対する書き込み操作をサポートおよび調整します。Amazon RDS for PostgreSQL は、次のバージョンの pgactive 拡張機能をサポートしています。

  • RDS for PostgreSQL 16.1 またはそれ以降の 16 バージョン

  • RDS for PostgreSQL 15.4-R2 以降のバージョン 15

  • RDS for PostgreSQL 14.10 以降のバージョン 14

  • RDS for PostgreSQL 13.13 以降のバージョン 13

  • RDS for PostgreSQL 12.17 以降のバージョン 12

  • RDS for PostgreSQL 11.22

注記

レプリケーション設定に複数のデータベースに対する書き込み操作があると、競合が発生する可能性があります。詳細については、「アクティブ/アクティブレプリケーションの競合の処理」を参照してください。

pgactive 拡張機能の初期化

RDS for PostgreSQL DB インスタンスの pgactive 拡張機能を初期化するには、rds.enable_pgactive パラメータの値を 1 に設定し、データベースに拡張を作成します。これを行うと、rds.logical_replication パラメータと track_commit_timestamp パラメータが自動的に有効になり、wal_level の値が logical に設定されます。

これらのタスクを実行するには、rds_superuser ロールとしてアクセス許可が必要です。

AWS Management Console または AWS CLI を使用して、必要な RDS for PostgreSQL DB インスタンスを作成できます。以下のステップでは、RDS for PostgreSQL DB インスタンスがカスタム DB パラメータグループに関連付けられていることを前提としています。カスタム DB パラメータグループの作成については、「Amazon RDS のパラメータグループ」を参照してください。

pgactive 拡張機能を初期化するには
  1. AWS Management Console にサインインし、Amazon RDS コンソール https://console.aws.amazon.com/rds/ を開きます。

  2. ナビゲーションペインで、RDS for PostgreSQL DB インスタンスを選択します。

  3. RDS for PostgreSQL DB インスタンスの [設定] タブを開きます。インスタンスの詳細で、[DB インスタンスパラメータグループ] リンクを見つけます。

  4. リンクを選択して、RDS for PostgreSQL DB インスタンスに関連付けられたカスタムパラメータを開きます。

  5. rds.enable_pgactive パラメータを見つけて 1 に設定し、pgactive 機能を初期化します。

  6. [Save changes] (変更の保存) をクリックします。

  7. Amazon RDS コンソールのナビゲーションペインで、[データベース] を選択します。

  8. RDS for PostgreSQL DB インスタンスを選択し、[アクション] メニューから [再起動] を選択します。

  9. DB インスタンスの再起動を確定して、変更を有効にします。

  10. DB インスタンスが使用可能になったら、psql または他の任意の PostgreSQL インスタンスを使用して RDS for PostgreSQL DB インスタンスに接続します。

    次の例では、RDS for PostgreSQL DB インスタンスに postgres という名前のデフォルトデータベースがあることを前提としています。

    psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master username --password --dbname=postgres
  11. pgactive が初期化されていることを確認するには、次のコマンドを実行します。

    postgres=>SELECT setting ~ 'pgactive' FROM pg_catalog.pg_settings WHERE name = 'shared_preload_libraries';

    pgactiveshared_preload_libraries にある場合、前述のコマンドは以下を返します。

    ?column? ---------- t
  12. 次のように拡張を作成します。

    postgres=> CREATE EXTENSION pgactive;
pgactive 拡張機能を初期化するには

AWS CLI を使用して pgactive を設定するには、次の手順に示すように、modify-db-parameter-group オペレーションを呼び出してカスタムパラメータグループ内の特定のパラメータを変更します。

  1. AWS CLI コマンドを使用して rds.enable_pgactive1 に設定し、RDS for PostgreSQL DB インスタンスの pgactive 機能を初期化します。

    postgres=>aws rds modify-db-parameter-group \ --db-parameter-group-name custom-param-group-name \ --parameters "ParameterName=rds.enable_pgactive,ParameterValue=1,ApplyMethod=pending-reboot" \ --region aws-region
  2. 次の AWS CLI コマンドを使用して RDS for PostgreSQL DB インスタンスを再起動し、pgactive ライブラリを初期化します。

    aws rds reboot-db-instance \ --db-instance-identifier your-instance \ --region aws-region
  3. インスタンスが使用可能になったら、psql を使用して RDS for PostgreSQL DB インスタンスに接続します。

    psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master user --password --dbname=postgres
  4. 次のように拡張を作成します。

    postgres=> CREATE EXTENSION pgactive;

RDS for PostgreSQL DB インスタンスのアクティブ/アクティブレプリケーションの設定

次の手順は、同じリージョンで PostgreSQL 15.4 以降を実行している 2 つの RDS for PostgreSQL DB インスタンス間でアクティブ/アクティブレプリケーションを開始する方法を示しています。マルチリージョンの高可用性の例を実行するには、2 つの異なるリージョンに Amazon RDS for PostgreSQL インスタンスをデプロイし、VPC ピアリングを設定する必要があります。詳細については、「VPC ピアリング接続」を参照してください。

注記

複数のリージョン間でトラフィックを送信すると、追加コストが発生する可能性があります。

次の手順では、RDS for PostgreSQL DB インスタンスが pgactive 拡張を使用して設定されていることを前提としています。詳細については、「pgactive 拡張機能の初期化」を参照してください。

pgactive 拡張を使用して最初の RDS for PostgreSQL DB インスタンスを設定するには

次の例は、pgactive グループの作成方法と、RDS for PostgreSQL DB インスタンスで pgactive 拡張を作成するために必要なその他の手順を示しています。

  1. psql または別のクライアントツールを使用して、最初の RDS for PostgreSQL DB インスタンスに接続します。

    psql --host=firstinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master username --password --dbname=postgres
  2. 次のコマンドを使用して RDS for PostgreSQL インスタンスにデータベースを作成します。

    postgres=> CREATE DATABASE app;
  3. 次のコマンドを使用して、接続先を新しいデータベースに切り替えます。

    \c app
  4. shared_preload_libraries パラメータに pgactive が含まれているかどうかを確認するには、次のコマンドを実行します。

    app=>SELECT setting ~ 'pgactive' FROM pg_catalog.pg_settings WHERE name = 'shared_preload_libraries';
    ?column? ---------- t
  5. 次の SQL ステートメントを使用して、サンプルのテーブルを作成および設定します。

    1. 次の SQL ステートメントを使用してサンプルテーブルを作成します。

      app=> CREATE SCHEMA inventory; CREATE TABLE inventory.products ( id int PRIMARY KEY, product_name text NOT NULL, created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP);
    2. 次の SQL ステートメントを使用して、サンプルデータをテーブルに入力します。

      app=> INSERT INTO inventory.products (id, product_name) VALUES (1, 'soap'), (2, 'shampoo'), (3, 'conditioner');
    3. 次の SQL ステートメントを使用して、テーブルにデータが存在することを確認します。

      app=>SELECT count(*) FROM inventory.products; count ------- 3
  6. 既存のデータベースで pgactive 拡張を作成します。

    app=> CREATE EXTENSION pgactive;
  7. 以下のコマンドを使用して pgactive グループを作成して初期化します。

    app=> SELECT pgactive.pgactive_create_group( node_name := 'node1-app', node_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=master username password=PASSWORD');

    node1-app は、pgactive グループ内のノードを一意に識別するために割り当てる名前です。

    注記

    パブリックにアクセス可能な DB インスタンスで、このステップを正常に実行するには、rds.custom_dns_resolution パラメータを 1 に設定して有効にする必要があります。

  8. DB インスタンスの準備が整っているかどうかを確認するには、次のコマンドを使用します。

    app=> SELECT pgactive.pgactive_wait_for_node_ready();

    コマンドが正常に完了した場合は、次の出力が表示されます。

    pgactive_wait_for_node_ready ------------------------------ (1 row)
2 番目の RDS for PostgreSQL インスタンスを設定して pgactive グループに参加させるには

次の例は、RDS for PostgreSQL DB インスタンスを pgactive グループに参加させる方法と、DB インスタンスに pgactive 拡張を作成するために必要なその他のステップを示しています。

次の手順では、RDS for PostgreSQL DB インスタンスpgactive 拡張を使用して設定されていることを前提としています。詳細については、「pgactive 拡張機能の初期化」を参照してください。

  1. psql を使用して、パブリッシャーから更新を受け取るインスタンスに接続します。

    psql --host=secondinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master username --password --dbname=postgres
  2. 次のコマンドを使用して、2 番目の RDS for PostgreSQL DB インスタンスにデータベースを作成します。

    postgres=> CREATE DATABASE app;
  3. 次のコマンドを使用して、接続先を新しいデータベースに切り替えます。

    \c app
  4. 既存のデータベースに pgactive 拡張を作成します。

    app=> CREATE EXTENSION pgactive;
  5. 次に示すように、RDS for PostgreSQL の 2 番目の DB インスタンスpgactive グループに参加させます。

    app=> SELECT pgactive.pgactive_join_group( node_name := 'node2-app', node_dsn := 'dbname=app host=secondinstance.111122223333.aws-region.rds.amazonaws.com user=master username password=PASSWORD', join_using_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD');

    node2-app は、pgactive グループ内のノードを一意に識別するために割り当てる名前です。

  6. DB インスタンスの準備が整っているかどうかを確認するには、次のコマンドを使用します。

    app=> SELECT pgactive.pgactive_wait_for_node_ready();

    コマンドが正常に完了すると、次の出力が表示されます。

    pgactive_wait_for_node_ready ------------------------------ (1 row)

    最初の RDS for PostgreSQL データベースが比較的大きい場合は、pgactive.pgactive_wait_for_node_ready() から復元操作の進行状況レポートを出力されることを確認できます。出力は次の例のようになります:

    NOTICE: restoring database 'app', 6% of 7483 MB complete NOTICE: restoring database 'app', 42% of 7483 MB complete NOTICE: restoring database 'app', 77% of 7483 MB complete NOTICE: restoring database 'app', 98% of 7483 MB complete NOTICE: successfully restored database 'app' from node node1-app in 00:04:12.274956 pgactive_wait_for_node_ready ------------------------------ (1 row)

    この時点から、pgactive は 2 つの DB インスタンス間でデータを同期します。

  7. 次のコマンドを使用して、2 番目の DB インスタンスのデータベースにデータがあるかどうかを確認できます。

    app=> SELECT count(*) FROM inventory.products;

    データが正常に同期されると、次の出力が表示されます。

    count ------- 3
  8. 次のコマンドを実行して新しい値を挿入します。

    app=> INSERT INTO inventory.products (id, product_name) VALUES ('lotion');
  9. 最初の DB インスタンスのデータベースに接続し、次のクエリを実行します。

    app=> SELECT count(*) FROM inventory.products;

    アクティブ/アクティブレプリケーションが初期化されると、出力は次のようになります。

    count ------- 4
pgactive グループから DB インスタンスをデタッチして削除するには

pgactive グループから DB インスタンスをデタッチして削除するには、次の手順に従います。

  1. 次のコマンドを使用して、最初のインスタンスから 2 番目の DB インスタンスをデタッチできます。

    app=> SELECT * FROM pgactive.pgactive_detach_nodes(ARRAY[‘node2-app']);
  2. 次のコマンドを使用して、2 番目の DB インスタンスから pgactive 拡張を削除します。

    app=> SELECT * FROM pgactive.pgactive_remove();

    拡張を強制的に削除するには

    app=> SELECT * FROM pgactive.pgactive_remove(true);
  3. 次のコマンドを使用して拡張をドロップします。

    app=> DROP EXTENSION pgactive;

アクティブ/アクティブレプリケーションの競合の処理

pgactive 拡張は、クラスターごとではなく、データベースごとに機能します。pgactive を使用する各 DB インスタンスは、独立したインスタンスであり、あらゆるソースからのデータ変更を受け入れることができます。変更が DB インスタンスに送信されると、PostgreSQL は変更をローカルにコミットし、pgactive を使用して他の DB インスタンスに非同期に変更をレプリケートします。2 つの PostgreSQL DB インスタンスが同じレコードをほぼ同時に更新すると、競合が発生する可能性があります。

pgactive 拡張は、競合の検出と自動解決のためのメカニズムを提供します。両方の DB インスタンスでトランザクションがコミットされた時点のタイムスタンプを追跡し、最新のタイムスタンプで変更を自動的に適用します。また、pgactive 拡張は、pgactive.pgactive_conflict_history テーブルで競合が発生した場合もログに記録します。

pgactive.pgactive_conflict_history は継続的に増大します。パージポリシーを定義するとよいでしょう。これを行うには、一部のレコードを定期的に削除するか、この関係のパーティションスキームを定義します (その後で対象のパーティションをデタッチ、ドロップ、切り捨てることができます)。パージポリシーを定期的に実装するには、 pg_cron 拡張機能を使用するというオプションがあります。pg_cron 履歴テーブルの例については、「PostgreSQL pg_cron 拡張機能を使用したメンテナンスのスケジュール」の次の情報を参照してください。

アクティブ/アクティブレプリケーションでのシーケンスの処理

pgactive 拡張を使用した RDS for PostgreSQL DB インスタンスは、2 つの異なるシーケンスメカニズムを使用して固有の値を生成します。

グローバルシーケンス

グローバルシーケンスを使用するには、CREATE SEQUENCE ステートメントを使用してローカルシーケンスを作成します。usingnextval(seqname) の代わりに pgactive.pgactive_snowflake_id_nextval(seqname) を使用すると、シーケンスの次の固有な値を取得できます。

次の例では、グローバルシーケンスを作成します。

postgres=> CREATE TABLE gstest ( id bigint primary key, parrot text );
postgres=>CREATE SEQUENCE gstest_id_seq OWNED BY gstest.id;
postgres=> ALTER TABLE gstest \ ALTER COLUMN id SET DEFAULT \ pgactive.pgactive_snowflake_id_nextval('gstest_id_seq');
分割シーケンス

分割ステップまたは分割シーケンスでは、通常の PostgreSQL シーケンスをノードごとに使用します。各シーケンスは同じ量ずつインクリメントされ、異なるオフセットから始まります。例えば、ステップ 100 の場合、ノード 1 は 101、201、301 などとしてシーケンスを生成し、ノード 2 は 102、202、302 などとしてシーケンスを生成します。このスキームは、ノードが長時間通信できない場合でも適切に機能しますが、設計者はスキーマを確立するときに最大ノード数を指定する必要があり、ノードごとの設定が必要になります。間違えると、シーケンスが重複しやすくなります。

次に示すように、ノードで目的のシーケンスを作成することで、このアプローチを pgactive で比較的簡単に設定できます。

CREATE TABLE some_table (generated_value bigint primary key);
postgres=> CREATE SEQUENCE some_seq INCREMENT 100 OWNED BY some_table.generated_value;
postgres=> ALTER TABLE some_table ALTER COLUMN generated_value SET DEFAULT nextval('some_seq');

次に、各ノードで setval を呼び出して、次のように異なるオフセットの開始値を指定します。

postgres=> -- On node 1 SELECT setval('some_seq', 1); -- On node 2 SELECT setval('some_seq', 2);

pgactive 拡張のパラメータリファレンス

次のクエリを使用すると、pgactive 拡張に関連するすべてのパラメータを表示できます。

postgres=> SELECT * FROM pg_settings WHERE name LIKE 'pgactive.%';

pgactive メンバー間のレプリケーションラグの測定

次のクエリを使用して、pgactive メンバー間のレプリケーションラグを表示できます。全体像を把握するには、すべての pgactive ノードでこのクエリを実行します。

postgres=# SELECT *, (last_applied_xact_at - last_applied_xact_committs) AS lag FROM pgactive.pgactive_node_slots; -{ RECORD 1 ]----------------+----------------------------------------------------------------- node_name | node2-app slot_name | pgactive_5_7332551165694385385_0_5__ slot_restart_lsn | 0/1A898A8 slot_confirmed_lsn | 0/1A898E0 walsender_active | t walsender_pid | 69022 sent_lsn | 0/1A898E0 write_lsn | 0/1A898E0 flush_lsn | 0/1A898E0 replay_lsn | 0/1A898E0 last_sent_xact_id | 746 last_sent_xact_committs | 2024-02-06 18:04:22.430376+00 last_sent_xact_at | 2024-02-06 18:04:22.431359+00 last_applied_xact_id | 746 last_applied_xact_committs | 2024-02-06 18:04:22.430376+00 last_applied_xact_at | 2024-02-06 18:04:52.452465+00 lag | 00:00:30.022089

pgactive 拡張の制限事項

  • すべてのテーブルには主キーが必要です。主キーがないと、更新や削除は許可されません。主キー列の値は更新しないでください。

  • シーケンスにはギャップがある場合があり、順序に従わないこともあります。シーケンスはレプリケートされません。詳細については、「アクティブ/アクティブレプリケーションでのシーケンスの処理」を参照してください。

  • DDL とラージオブジェクトはレプリケートされません。

  • セカンダリの一意のインデックスはデータの相違を引き起こす可能性があります。

  • 照合順序はグループ内のすべてのノードで同一である必要があります。

  • ノード間の負荷分散はアンチパターンです。

  • トランザクションが大きいと、レプリケーションの遅延が発生する可能性があります。