originパラメーターによる双方向の論理レプリケーション - PostgreSQL 16でコミットされた機能の紹介:技術者Blog
PostgreSQLインサイド


Vigneshwaran C
FUJITSU Limited
Software Open Innovation Business Unit Data Management Division
Software Lead Developer
はじめに
このブログでは、PostgreSQL 16の新機能である、originパラメーターによるフィルタリングを使用した双方向の論理レプリケーションについて簡単に紹介します。
背景
通常、論理レプリケーションのパブリッシュとサブスクライブモデルを使用する場合、パブリッシュされたテーブルのすべての更新データは、データのorigin(起点)に関係なく、適切なサブスクライバーにレプリケートされます。論理レプリケーションのデータをそのoriginでフィルタリングする新しい機能により、そのパブリッシャーで発生した更新データのみがレプリケートされるように、レプリケーションを制限できるようになりました。これは、レプリケーションのプライマリーノード間での再帰(同じデータの無限レプリケーション)を回避するために使用できます。この機能の重要な点は、WALレコードにデータのoriginが含まれていることです。これは、パブリッシャーがそれに従ってパブリッシュするのに役立ちます。
目次
機能の概要
PostgreSQLのCREATE SUBSCRIPTION文に新しいパラメーター「origin」 が追加されました。これは、サブスクリプションがパブリッシャーに対して、originに関連付けられていない更新データのみを送るか、あるいはoriginの関連付けに関係なく更新データを送るかを指定します。
originにNONEを設定すると、サブスクリプションはoriginを持たない更新データのみを送信するようにパブリッシャーに要求します。
originにANYを設定すると、パブリッシャーはoriginに関係なく更新データを送信します。デフォルトはANYです。
図1:originパラメーターによるフィルタリングの概要
-
注意)
上記origin=NONEの例では、ノード2は「node1_data」行のデータをノード3にレプリケートしません。このデータはノード1からのものであるためです。
CRATE SUBSCRIPTION構文の改良
次に、簡略化したCREATE/ALTER SUBSCRIPTION構文を示します。PostgreSQL 16で追加された新しいoriginパラメーターを強調表示しています。
CREATE SUBSCRIPTION <sub-name> CONNECTION 'conninfo' PUBLICATION <pub-list> [WITH (origin = NONE|ANY)]
ALTER SUBSCRIPTION <sub-name> SET (origin = NONE|ANY)
例1
node1=# CREATE SUBSCRIPTION sub_host1_local_data
node1-# CONNECTION 'host=192.168.1.50 port=5432 user=dba1 dbname=salesdb'
node1-# PUBLICATION pub_host1 WITH (origin=NONE);
例2
node2=# CREATE SUBSCRIPTION sub_host1_all_data
node2-# CONNECTION 'host=192.168.1.50 port=5432 user=dba1 dbname=salesdb'
node2-# PUBLICATION pub_host1 WITH (origin=ANY);
origin=NONEの場合のフィルタリング
パブリッシャー上のwalsenderプロセスはWALファイルをレコード単位で読み取り、デコードします。originパラメーターにNONEが設定されている場合、WALレコードのデコード中、出力プラグインはoriginが関連付けられているすべてのデータを除外します。
図2:origin=NONEでフィルタリングされたトランザクション
プライマリーノード間のレプリケーション
プライマリーノード間のレプリケーションは、いずれのプライマリーノードによって実行された書込み操作もレプリケートするため、マルチマスターデータベース環境を構築するのに便利です。さまざまなシナリオでプライマリーノード間のレプリケーションを作成する手順を次に示します。
2つのプライマリーノード間のレプリケーション設定
次の手順では、両方のプライマリーノードにテーブルデータが存在しないときに、2つのプライマリーノード(primary1とprimary2)間でレプリケーションを設定する方法を示します。
-
注意)
セットアップが完了するまで、ノードprimary1およびノードprimary2のテーブルt1に対して、いずれの操作も実行されないようにしてください。
図3:2つのプライマリーノード間の双方向レプリケーション
-
ノードprimary1にパブリケーションを作成します。
primary1=# CREATE PUBLICATION pub_pri1 FOR TABLE t1;
CREATE PUBLICATION
-
ノードprimary2にパブリケーションを作成します。
primary2=# CREATE PUBLICATION pub_pri2 FOR TABLE t1;
CREATE PUBLICATION
-
primary2からprimary1へのサブスクリプションを作成します。
primary2=# CREATE SUBSCRIPTION sub_pri2_pri1
primary2-# CONNECTION 'dbname=foo host=primary1 user=repuser'
primary2-# PUBLICATION pub_pri1 WITH (origin = NONE);
CREATE SUBSCRIPTION
-
primary1からprimary2へのサブスクリプションを作成します。
primary1=# CREATE SUBSCRIPTION sub_pri1_pri2
primary1-# CONNECTION 'dbname=foo host=primary2 user=repuser'
primary1-# PUBLICATION pub_pri2 WITH (origin = NONE);
CREATE SUBSCRIPTION
この段階で、primary1とprimary2のノード間のレプリケーションのセットアップは完了です。primary1からの増分の更新データはprimary2にレプリケートされ、その逆も同様です。
以降の手順を実施する前に、以下のSQL文を実行し、ここまでのセットアップが完了しているかを確認します。まず、ノードprimary1のテーブルにデータを挿入します。
primary1=# INSERT INTO t1 VALUES('node1_data1');
INSERT 0 1
次に、ノードprimary2のテーブルを読み取ります。挿入されたデータはレプリケートされます。
primary2=# SELECT * FROM t1;
c1
-------------
node1_data1
(1 row)
では、同じテストをprimary2からprimary1の逆方向に実行します。primary2にデータを挿入してみましょう。テーブルには、上記のprimary1からレプリケートされたデータがすでに含まれていることに注意してください。
primary2=# INSERT INTO t1 VALUES('node2_data1');
INSERT 0 1
Primary2=# SELECT * FROM t1;
c1
-------------
node1_data1
node2_data1
(2 rows)
最後に、primary1のテーブルを確認してみましょう。primary2からデータがレプリケートされていることがわかります。
primary1=# SELECT * FROM t1;
c1
-------------
node1_data1
node2_data1
(2 rows)
3つめのプライマリーノードの追加
次の手順では、どのプライマリーノードにもテーブルt1にデータがないときに、既存のセットアップに新しいプライマリーノード(primary3)を追加する方法を示します。これには、ノードprimary1とprimary2にサブスクリプションを作成してprimary3からデータをレプリケートし、primary3にサブスクリプションを作成してprimary1とprimary2からデータをレプリケートする必要があります。
これらの手順は、primary1とprimary2間のレプリケーション設定がすでに完了していることを前提としています。
図4:3つのプライマリーノード間の双方向レプリケーション
-
ノードprimary3にパブリケーションを作成します。
primary3=# CREATE PUBLICATION pub_pri3 FOR TABLE t1;
CREATE PUBLICATION
-
primary1からprimary3へのサブスクリプションを作成します。
primary1=# CREATE SUBSCRIPTION sub_pri1_pri3
primary1-# CONNECTION 'dbname=foo host=primary3 user=repuser'
primary1-# PUBLICATION pub_pri3 WITH (origin = NONE);
CREATE SUBSCRIPTION
-
primary2からprimary3へのサブスクリプションを作成します。
primary2=# CREATE SUBSCRIPTION sub_pri2_pri3
primary2-# CONNECTION 'dbname=foo host=primary3 user=repuser'
primary2-# PUBLICATION pub_pri3 WITH (origin = NONE);
CREATE SUBSCRIPTION
-
primary3からprimary1へのサブスクリプションを作成します。
primary3=# CREATE SUBSCRIPTION sub_pri3_pri1
primary3-# CONNECTION 'dbname=foo host=primary1 user=repuser'
primary3-# PUBLICATION pub_pri1 WITH (origin = NONE);
CREATE SUBSCRIPTION
-
primary3からprimary2へのサブスクリプションを作成します。
primary3=# CREATE SUBSCRIPTION sub_pri3_pri2
primary3-# CONNECTION 'dbname=foo host=primary2 user=repuser'
primary3-# PUBLICATION pub_pri2 WITH (origin = NONE);
CREATE SUBSCRIPTION
これで、ノードprimary1、primary2、およびprimary3間のレプリケーションのセットアップが完了しました。プライマリーノードで行われた増分の更新データは、他の2つのノードにレプリケートされます。
制限事項
前述したレプリケーション設定の例には、いくつかの制限事項があります。
-
既存のテーブルデータを持つ新しいプライマリーノードの追加はサポートされていません。
-
CREATE SUBSCRIPTION文でcopy_data=trueとorigin=NONEのパラメーターを組み合わせて使用する場合、初期同期テーブルデータはパブリッシャーから直接コピーされます。これは、そのデータの真のoriginを知ることができないことを意味します。
パブリッシャーがサブスクリプション機能も持つ場合、コピーされたテーブルデータはさらに上流originから送信された可能性があります。このシナリオでは検出されて、ユーザーに警告が記録されますが、警告は潜在的な問題を引き起こす可能性にすぎません。コピーされたデータのoriginが本当に期待どおりであるかどうかを確認するのはユーザーの責任です。(パブリッシャーで作成された他のサブスクリプションが原因で)ローカル以外のoriginを含む可能性のあるテーブルを特定するには、次のSQLクエリを実行してください。
#以下の<pub-names>を照会するパブリケーション名に置き換えてください。
SELECT DISTINCT PT.schemaname, PT.tablename
FROM pg_publication_tables PT,
pg_subscription_rel PS
JOIN pg_class C ON (C.oid = PS.srrelid)
JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE N.nspname = PT.schemaname AND
C.relname = PT.tablename AND
PT.pubname IN (<pub-names>);
注意事項
-
システムの双方向レプリケーションを設定する場合、ユーザーは論理レプリケーションのコンフリクトのリスクを最小限に抑える方法でスキーマを設計する必要があります。この問題の詳細については、PostgreSQL文書の「Conflicts」の節を参照してください。
-
現在、論理レプリケーションにはいくつかの制限、または見方によっては不足している機能があります。詳細については、PostgreSQL文書の「Restrictions」の節を参照してください。
-
プライマリーノード間のレプリケーションを設定するには、さまざまなプライマリーノードで複数の手順を実行する必要があります。すべての操作がトランザクション処理されるわけではないため、バックアップを取ることをお勧めします。PostgreSQL文書の「Backup and Restore」の節で説明されているようにバックアップを取ることができます。
今後に向けて
「origin」パラメーターの追加は、マルチマスター論理レプリケーションをサポートするための第一歩です。この機能により、論理レプリケーションの柔軟性が向上します。富士通OSSチームはPostgreSQLコミュニティと共に、PostgreSQL論理レプリケーションの機能強化と追加を引き続き支援していきます。
この記事で説明したキーポイントの詳細については、以下を参照ください。
-
PostgreSQL文書のCREATE SUBSCRIPTION文のページでは、「origin」の使用方法に関する構文と詳細な仕様が記載されています。
- PostgreSQL:Documentaiton: 16: CREATE SUBSCRIPTION(PostgreSQLオフィィシャルのページへ)
-
PostgreSQL文書の「Replication Progress Tracking」のページでは、レプリケーションのoriginについて、この記事より詳細に説明しています。
- PostgreSQL:Documentaiton: 16: Replication Progress Tracking(PostgreSQLオフィィシャルのページへ)
-
PostgreSQLのGitHubソースコードのメインパッチは、originを使って論理レプリケーションをフィルタリングできるようにします。
- Allow users to skip logical replication of data having origin.(GitHub.comのページへ)
2023年11月8日公開
富士通のソフトウェア公式チャンネル(YouTube)
-
- 富士通のミドルウェア製品のご紹介や各種イベント・セミナーの講演内容、デモンストレーションなどの動画をご覧いただけます。
- 富士通のミドルウェア製品のご紹介や各種イベント・セミナーの講演内容、デモンストレーションなどの動画をご覧いただけます。
PostgreSQLについてより深く知る
PostgreSQLに興味をお持ちのお客様はこちらのコンテンツもお勧めです。ぜひご覧ください。
本コンテンツに関するお問い合わせ
お電話でのお問い合わせ
-
富士通コンタクトライン(総合窓口)
0120-933-200受付時間:9時~12時および13時~17時30分(土曜日・日曜日・祝日・当社指定の休業日を除く)