[アップデート] Amazon RDS for PostgreSQL 15.4-R2 で pgactive 拡張を使ったアクティブ/アクティブ構成を導入してみた

2023.10.11

いわさです。

2023 年 10 月 5 日より Amazon RDS の PostgreSQL にて、15.4-R2 が利用可能になりました。

October 5, 2023
RDS for PostgreSQL now supports version versions 15.4-R2, 14.9-R2, 13.12-R2, and 12.16-R2.

Document history for the RDS for PostgreSQL release notes - Amazon Relational Database Service

このリリースに併せて、新しく pgactive という拡張機能が使えるようになっています。

この拡張を使うと複数のマスター間でのアクティブ/アクティブなレプリケーションを行うことが出来ます。

この構成のユースケースが公式ブログ内で言及されており、マルチリージョンで高可用性なデータベースクラスター、アプリケーションとデータベース間の書き込み遅延の削減、アプリケーションのブルー/グリーンアップデートの実行、書き込み可能な複数システム間のデータ移行などが挙げられています。

この記事では東京リージョンと大阪リージョンの RDS 間でレプリケーション構成を行ってみましたので手順などを紹介します。

Amazon RDS for PostgreSQL の 15.4-R2 以上で利用可能

今回の機能を使うための前提条件としてはエンジンバージョンが PostgreSQL 15.4-R2 以上である必要があります。
先日リリースされたばかりのバージョンですので利用にあたっては多くの環境で、まずエンジンバージョンのバージョンアップが必要となります。

今回は新規作成で進めたいと思います。15.4-R2 を東京リージョンと大阪リージョンに作成します。

この拡張機能は複数のインスタンス間でレプリケーションのための通信が可能な状態である必要があります。
そのため、プライベートアクセスのみを許可するインスタンスの場合は VPC ピアリングなどネットワーク経路の確保がまず必要になります。

今回は私はパブリックアクセス可能なインスタンスを東京リージョンと大阪リージョンにデフォルト VPC 上に用意しました。
この場合でもレプリケーション構成は可能ですが、後述のカスタム DNS の設定が追加で必要となります。

バックアップや拡張モニタリング、暗号化などの一式のオプション設定は今回はすべて OFF で実施しました。
pgactive の有効化にあたって、パラメータグループをデフォルトから変更する必要がありますのでカスタムパラメータグループを用意しておきます。

パラメータは次のrds.enable_pgactive0から1に変更します。

また、パブリックアクセス可能なインスタンス間で構成する場合は、アウトバウンド時のカスタム DNS 構成を ON にする必要があります。

このオプションの詳細については次のドキュメントを確認してください。

pgactive を構成する

RDS for PostgreSQL インスタンスに接続し、拡張の作成やレプリケーション設定を行っていきます。

なおパラメータグループの変更を行った後に次のように接続時にライブラリのエラーが発生する場合は、インスタンスを再起動させてください。

% psql -h hoge1011tokyo.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com -U postgres
Password for user postgres: 
psql: error: connection to server at "hoge1011tokyo.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com" (52.197.22.176), port 5432 failed: FATAL:  pgactive must be loaded via shared_preload_libraries

確認用のデータベースなどを作成

まずはレプリケーション確認用のサンプルデータベースなどを作成しておきます。
東京リージョンでデータベース、テーブル、レコードを作成し、大阪リージョンではデータベースまで作成しておきます。

東京リージョン

postgres=> \c tokyodb
psql (14.9 (Homebrew), server 15.4)
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
You are now connected to database "tokyodb" as user "postgres".
tokyodb=> create table piyo (id int primary key, name2 text);
CREATE TABLE
tokyodb=> insert into piyo values (1, '111');
INSERT 0 1
tokyodb=> insert into piyo values (2, '222');
INSERT 0 1
tokyodb=> insert into piyo values (3, '333');
INSERT 0 1
tokyodb=> select * from piyo;
 id | name2 
----+-------
  1 | 111
  2 | 222
  3 | 333
(3 rows)

大阪リージョン

postgres=> \c osakadb;
psql (14.9 (Homebrew), server 15.4)
WARNING: psql major version 14, server major version 15.
         Some psql features might not work.
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
You are now connected to database "osakadb" as user "postgres".
osakadb=>

レプリケーショングループの作成

作成したデータベース上で pgactive 拡張を有効化し、pgactive のレプリケーショングループを作成します。
ここでの流れとしては東京リージョンでレプリケーショングループを作成し、大阪リージョンではそのレプリケーショングループにノードを作成します。

東京リージョンでレプリケーショングループを作成

東京リージョンではレプリケーショングループの作成を行います。
pgactive_create_group()を使用して作成することが出来ます。

東京リージョン

tokyodb=> CREATE EXTENSION pgactive;
CREATE EXTENSION
tokyodb=> SELECT pgactive.pgactive_create_group(node_name := 'tokyo1', node_dsn := 'dbname=tokyodb host= hoge1011tokyo.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com user=postgres password=hogehoge');
 pgactive_create_group 
-----------------------
 
(1 row)

]

pgactive.pgactive_wait_for_node_ready()を使うことで DB インスタンスの準備状態を確認することが出来ます。
次の応答が返ってくれば準備が出来ている状態です。応答が無い場合は準備がまだ出来てない状態となります。

tokyodb=> SELECT pgactive.pgactive_wait_for_node_ready();
 pgactive_wait_for_node_ready 
------------------------------
 
(1 row)

作成したレプリケーショングループに大阪リージョンのノードを参加させる

続いて、東京リージョンで作成したレプリケーショングループに、大阪リージョンのインスタンスからノードを定義しつつレプリケーショングループへ参加させます。

大阪リージョン

osakadb=> SELECT pgactive.pgactive_join_group(node_name := 'osaka1', node_dsn := 'dbname=osakadb host= hoge1011osaka.clfqru7bvdd5.ap-northeast-3.rds.amazonaws.com user=postgres password=hogehoge', join_using_dsn := 'dbname=tokyodb host= hoge1011tokyo.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com user=postgres password=hogehoge');
 pgactive_join_group 
---------------------
 
(1 row)

osakadb=> SELECT pgactive.pgactive_wait_for_node_ready();
 pgactive_wait_for_node_ready 
------------------------------
 
(1 row)

pgactive_join_group()では、先程と異なりjoin_using_dsnパラメータで東京リージョンのデータベースを指定しています。

レプリケーションの動作確認

まずはレプリケーショングループに参加直後の大阪リージョンのデータベースを確認してみます。
この時点で東京リージョンで作成したテーブルおよびレコードがレプリケーションされていることが確認出来ます。

osakadb=> select * from piyo;
 id | name2 
----+-------
  1 | 111
  2 | 222
  3 | 333
(3 rows)

この状態で大阪リージョンで新しいレコードを作成し、直後に東京リージョンで取得してみます。

tokyodb=> select * from piyo;
 id | name2  
----+--------
  1 | 111
  2 | 222
  3 | 333
  4 | osaka1
(4 rows)

即反映されました。

東京リージョンと大阪リージョンそれぞれで削除や更新なども一通り確認してみましたが双方向に同期されていることが確認出来ました。

レプリカラグの確認

アクティブ/アクティブのデータベースを使う場合は競合が発生した場合の動作や整合性、レプリケーション時のラグなど、様々な制約についてアプリケーション側で十分に考慮する必要があります。

本記事では色々と実験したかったのですが、ラグが小さくて手動だと競合の確認が出来ず、レプリカラグの確認のみ行ってみました。セキュリティグループなどを調整して別途競合発生時の検証は行いたいと思いますが、先勝ち・後勝ち・カスタムと結構細かく調整は出来るようです。

レプリカラグの確認は pgactive の統計情報から計算することが出来ます。
次のコマンドで統計情報を取得することが出来ます。

tokyodb=> select * from pgactive.pgactive_node_slots;
 node_name |                  slot_name                   | slot_restart_lsn | slot_confirmed_lsn | walsender_active | walsender_pid |  sent_lsn  | write_lsn  | flush_lsn  | replay_lsn | last_sent_xact_id |    last_sent_xact_committs    |       last_sent_xact_at       | last_applied_xact_id |  last_applied_xact_committs   |     last_applied_xact_at      
-----------+----------------------------------------------+------------------+--------------------+------------------+---------------+------------+------------+------------+------------+-------------------+-------------------------------+-------------------------------+----------------------+-------------------------------+-------------------------------
 osaka1    | pgactive_16621_7288481165929861917_0_16621__ | 0/480000D8       | 0/48000110         | t                |          1228 | 0/48000110 | 0/48000110 | 0/48000110 | 0/48000110 |               894 | 2023-10-10 23:49:26.503909+00 | 2023-10-10 23:49:26.504563+00 |                  894 | 2023-10-10 23:49:26.503909+00 | 2023-10-10 23:49:26.510307+00
(1 row)

ここで確認出来るのはノードごとの統計情報となっており、トランザクションの最終送信日時と適用日時からラグを計算することが出来ます。
このあたりの計算方法は次の公式ドキュメントにも紹介されています。

先程の処理結果から確認してみると次のように、東京大阪間でかなり高速にレプリケーションされています。

tokyodb=> SELECT node_name, last_applied_xact_id::int - last_sent_xact_id::int AS lag_xid, last_sent_xact_at - last_applied_xact_at AS lag_time FROM pgactive.pgactive_node_slots;
 node_name | lag_xid |     lag_time     
-----------+---------+------------------
 osaka1    |       0 | -00:00:00.005744
(1 row)

さいごに

本日は Amazon RDS for PostgreSQL 15.4-R2 で pgactive 拡張を使ったアクティブ/アクティブ構成を導入してみました。
色々と評価したい点は残っているのですが、まずは導入に関してはネットワーク経路が確保されていれば簡単に構成出来ることが確認出来ました。

なお、pgactive 公式ドキュメントには次の制限事項が記載されています。

  • すべてのテーブルには主キーが必要です。それ以外の場合は Update と Delete は許可されません。主キー列の値は更新しないでください。
  • シーケンスにはギャップがある場合があり、順序に従わない場合もあります。シーケンスは複製されません。
  • DDL とラージオブジェクトはレプリケートされません。
  • セカンダリのユニークインデックスはデータの相違の原因となることがあります。
  • 照合順序はグループ内のすべてのノードで同一である必要があります。
  • ノード間の負荷分散はアンチパターンです。
  • トランザクションが大きいと、レプリケーションの遅延が発生する可能性があります。

上記制限事項以外にも整合性などの挙動からアプリケーションや運用面での考慮点も多く、導入にあたっては慎重に検討する必要がありますが RDS for PostgreSQL で実装する際の選択肢として覚えておくと良いですね。