PostgreSQLのロジカルレプリケーションをマスターする:柔軟なデータ同期と実践ガイド

Database tutorial - IT technology blog
Database tutorial - IT technology blog

なぜStreaming ReplicationではなくLogical Replicationを選ぶのか?

ストリーミングレプリケーション(物理レプリケーション)は、クラスタ全体をプライマリノード from スタンバイノードへ複製する非常に一般的なソリューションです。しかし、現実はそう甘くありません。実際のプロジェクトでは、物理的な複製が重すぎたり、不可能だったりするケースに遭遇します。例えば、レポート作成のために重要な5つのテーブルだけをレプリケーション用のノードに送りたい場合や、PostgreSQL v12とv16のように異なるバージョン間でデータを同期したい場合などです。

そこで力を発揮するのが、ロジカルレプリケーション(Logical Replication)です。ディスク上の生のデータブロックをコピーする代わりに、変更内容(INSERT、UPDATE、DELETE)を論理的なデータストリームにデコードします。この仕組みにより、特定のテーブルを正確に選択したり、行フィルタリング(row filter)を使用して帯域幅を最適化したりすることが可能になります。

以前、2.5TBのモノリスDBから新しいマイクロサービスへ顧客データを移行する案件を担当しました。従来のdump/restoreを使用すると、システムを少なくとも4〜6時間は停止させる必要がありました。しかし、ロジカルレプリケーションを活用したことで、ダウンタイムを30秒未満に短縮できました。これは、DevOpsチームが接続文字列を切り替えるのに必要な時間だけで済みました。

PublicationとSubscriptionの基本概念

スムーズに運用するために、2つの重要な概念を理解しておく必要があります:

  • Publication(パブリッシャー側): ここで「配信」したいテーブルのリストを定義します。FOR ALL TABLESを選択するか、特定のテーブルリストを指定できます。
  • Subscription(サブスクライバー側): データを受け取る側の登録設定です。1つのサブスクライバーが複数のパブリッシャーに接続できるため、5〜10箇所の拠点のデータベースから中央のデータウェアハウスにデータを集約する際に非常に便利です。

注意: ロジカルレプリケーションはテーブル構造(Schema/DDL)を同期しません。接続する前に、送信先(ターゲット側)に同じ構造のテーブルがあらかじめ作成されていることを確認してください。

詳細な構築手順

ステップ1:パブリッシャー(ソース側)の設定

postgresql.confファイルを開き、wal_levelパラメータを探します。デフォルト値は通常replicaですが、デコードに必要な情報を記録するためにlogicalに変更する必要があります。

# postgresql.conf の最小構成
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10

設定を反映させるためにPostgreSQLを再起動してください。次に、同期専用のユーザーを作成します:

CREATE ROLE replicator_user WITH REPLICATION LOGIN PASSWORD 'strong_password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator_user;

その後、必要なテーブル(例:orderscustomers)に対してパブリケーションを作成します:

CREATE PUBLICATION my_selective_pub FOR TABLE orders, customers;

ステップ2:サブスクライバー(ターゲット側)の設定

最初のステップは、データの枠組み(スキーマ)をコピーすることです。最も速い方法は、不要なデータを含めないように--schema-onlyフラグを付けてpg_dumpを使用することです:

pg_dump -h source_host -U username -s -t orders -t customers source_db | psql -h target_host -U username target_db

最後に、CREATE SUBSCRIPTIONコマンドを実行してデータの受信を開始します:

CREATE SUBSCRIPTION my_selective_sub 
CONNECTION 'host=source_host port=5432 user=replicator_user password=strong_password dbname=source_db' 
PUBLICATION my_selective_pub;

このコマンドが正常に実行されると、PostgreSQLは「初期コピー(Initial Copy)」を開始し、既存の全データをターゲット側に流し込んでから、リアルタイム同期モードに移行します。

実践的な経験とハマりやすい落とし穴

1. 主キー(Primary Key)に関するトラブル

UPDATEDELETEを同期するには、テーブルに主キーが必要です。主キーがない場合、即座にエラーが発生します。どうしても主キーを設定できない場合は、REPLICA IDENTITY FULLを設定する必要がありますが、ソースサーバーのCPU負荷が大幅に増加するため注意が必要です。

2. シーケンスの同期忘れ

ロジカルレプリケーションは、シーケンス(オートインクリメント列)の値を自動的に更新しません。新しいDBに切り替える際、手動でシーケンスのMAX(id)を更新しないと、新しいレコードを挿入したときに主キー重複エラーでアプリケーションがクラッシュします。

3. レプリケーションスロットによるディスク圧迫

これはシステムをダウンさせる最も早い原因です。サブスクライバーの接続が切れると、パブリッシャーは再接続を待つためにすべてのWALファイルを保持し続けます。サブスクライバーのネットワーク障害により、わずか3時間でディスクが200GBも消費され、サーバーがハングアップしたのを目の当たりにしたことがあります。ディスク容量とスロットの状態には必ずアラートを設定しておきましょう。

4. 遅延(Lag)の監視

データに遅延が発生していないか確認するには、パブリッシャーノードで以下のクエリを実行します:

SELECT application_name, client_addr, state, 
       pg_wal_lsn_diff(sent_lsn, write_lsn) AS write_lag 
FROM pg_stat_replication;

おわりに

ロジカルレプリケーションは強力なツールですが、慎重な運用が求められます。マイクロサービスの分離からBI/データウェアハウス用のデータ集約まで、データアーキテクチャに柔軟性をもたらしてくれます。ただし、ディスク溢れのリスクを避けるために、レプリケーションスロットの監視は徹底してください。この実戦経験に基づいた共有が、より安定した効率的なシステム構築の助けになれば幸いです。

Share: