論理レプリケーション解説 ~ 仕組み、設定方法 ~
PostgreSQLインサイド

データベースでの「レプリケーション」とは、データベースのレプリカ(複製)を作成することです。レプリケーションの方式には、データベースクラスタ全体を複製する「ストリーミングレプリケーション(物理レプリケーション)」と、スキーマ単位やテーブル単位に複製する「ロジカルレプリケーション(論理レプリケーション)」があります。
この記事の前半では、論理レプリケーションの概要、用途、ストリーミングレプリケーションとの違い、構築可能な構成を説明します。後半では、設定方法や基本的な使い方についてサンプルを交えて解説します。
本記事の設定方法などの検証は、PostgreSQL 15で実施しています。

なお、ストリーミングレプリケーションの概要を押さえておくことで、論理レプリケーションの理解がより深まります。以下の記事で解説していますので、まだ読まれていない方は、ぜひ先にお読みください。

目次

1. 論理レプリケーションとは

論理レプリケーションを適切に使う上で、レプリカアイデンティティなどの専門用語を理解しつつ機能概要を押さえることは重要です。以降で、専門用語を解説しつつ論理レプリケーションの機能概要を以下の順で説明します。

機能概要

論理レプリケーションとは、レプリカアイデンティティ(主キーなど)に基づいて、データオブジェクトと、それに対する変更に関する情報(WAL)を、論理的な情報に変換して複製(転送)する機構です。
データの複製元をパブリッシャー、複製先をサブスクライバーと呼びます(PUB/SUBモデルをベースにしています)。また、レプリケーション対象のテーブルなどを指定したオブジェクトをパブリケーション(publication)、レプリケーション対象のパブリケーションとの接続先を定義したオブジェクトをサブスクリプション(subscription)と呼びます。

論理レプリケーションのイメージを以下に示します。

論理レプリケーションのイメージ

図1:論理レプリケーションのイメージ

レプリカアイデンティティとは

前述したレプリカアイデンティティとは、パブリケーションとサブスクリプションとのレコードを対応づけるためのカラム名のことです。例えば、パブリケーションとサブスクリプションの両テーブルのカラムに主キーやユニークキーを付けることで、レプリカアイデンティティを作成できます。

レプリカアイデンティティは、以下を実現するために必要です。

  • 対象テーブルに対してUPDATE文とDELETE文を実行する
  • パブリケーションで行フィルターを設定する
  • パブリケーションで列フィルターを設定する

なお、論理レプリケーションで複製する対象がINSERTのみ、かつ、行フィルターや列フィルターを使わない場合、レプリカアイデンティティは必要ありません。行フィルターと列フィルターの機能概要および使い方に関しては、本記事の後半で説明します。

利用例

以下の要件に対して、論理レプリケーションを利用できます。

  • 特定データ(テーブル)を他のデータベースに共有
  • 複数のデータベースに散らばったデータの統合や整理
  • OSやPostgreSQLのバージョンアップ

例えば、「複数のデータベースに散らばったデータの統合や整理」のユースケースでは、図2のように論理レプリケーションを利用することで、下記の要件を満たせます。

要件)
A社とB社の合併により新会社が設立された。業務統合をする上で、データ統合が必要であるが、A社、B社ともに、業務を停止することが許されず、かつ、従業員テーブルにも更新が入る。この状況で、新会社のデータベースに統合された従業員テーブルを動的に構築することを要件とする。

経営統合による従業員テーブルの動的な統合および整理

図2:経営統合による従業員テーブルの動的な統合および整理

利用者起点での機能の十分性

PostgreSQLのバージョンアップごとに、論理レプリケーションに対する以下の機能追加や改善が実施されました。

  • PostgreSQL 14での論理レプリケーションの開発項目:実用レベルへの基盤作りを主とした開発
    システムビューpg_stat_replication_slots、二相コミット基盤、実行中の大規模トランザクションをストリーム、安定性向上
  • PostgreSQL 15での論理レプリケーションの開発項目:適応範囲を広げる機能を主に開発
    コンフリクト対処、行フィルター、列フィルター、スキーマフィルター、通信の改善、二相コミット

ストリーミングレプリケーションとの違い

PostgreSQLのレプリケーションには、ストリーミングレプリケーションと論理レプリケーションがあります。PostgreSQL 15で利用できるストリーミングレプリケーションと論理レプリケーションの違いを以下の表にまとめます。

表1 ストリーミングレプリケーションと論理レプリケーションの違い

比較項目 ストリーミングレプリケーション 論理レプリケーション
利用例 高可用性、災害対策(ディザスタリカバリー)、参照負荷分散、バックアップ 特定データ(テーブル)の複製、複数のデータベースの情報を統合/整理、運用中のPostgreSQLのメジャーバージョンアップ、異なるPostgreSQLバージョン間のレプリケーション、異なるOS間のレプリケーション(例:WindowsからLinux)、バックアップ
対応バージョン PostgreSQL 9.0以降 PostgreSQL 10以降
レプリケーション対象 すべてのオブジェクト テーブルのみ
レプリケーション単位 データベースクラスタ 単一テーブル、複数テーブル、全テーブル、 スキーマ内のすべてのテーブル(PostgreSQL 15以降)、複数スキーマ、行/カラム(PostgreSQL 15以降)
レプリケーションされる操作 WALが出力されるすべての操作 INSERT、UPDATE、DELETE、 TRUNCATE(PostgreSQL 11以降)、COMMIT/ROLLBACK ※INSERT、UPDATE、DELETE、TRUNCATEに関してはレプリケーション対象の操作を選択可能
同期 同期/非同期(デフォルト) 同期/非同期(デフォルト)
転送データ WALレコード(トランザクションログ) WALをデコードした論理的な情報
レプリケーション元とレプリケーション先の環境 同一OS、同一メジャーバージョン 同一/異なるOS、同一/異なるメジャーバージョン
レプリケーション先ノードのアクセス 参照のみ 参照、更新(更新時は制約違反によるコンフリクトに注意)
レプリケーション先トリガー 不可 可(レプリケーション先テーブルにトリガーの設定が可能)

備考.上記表内の情報は今後のバージョンアップで変わる可能性があります。

2. 論理レプリケーションの仕組み

論理レプリケーションの複製や内部動作の流れを把握することで、論理レプリケーションを安全に業務へ導入できます。また、構築可能な構成を押さえておくことで、無駄のないシステムを設計できます。
ここでは、論理レプリケーションの採用できる構成から内部の仕組みについて説明します。

基本構成

論理レプリケーションの仕組みを理解するために、何を転送するのか、どのように転送するのかを、詳しく説明します。

構成要素

論理レプリケーションは、1つ以上のパブリケーション、1つ以上のサブスクリプション、レプリケーションの状態を保持するオブジェクトであるレプリケーションスロット、複製元のテーブル、複製先のテーブルで構成されます。

以下の図に示した構成を基本として、カスケード構成など様々な構成を採用できます。採用可能な構成に関しては、次節で説明します。

論理レプリケーションの基本構成

図3:論理レプリケーションの基本構成

レプリケーションの流れ

PostgreSQLは、更新情報をトランザクションログ(以降、WALと略します)として保存します。論理レプリケーションでは、このWALをデコードし、パブリッシャー内にあるwalsenderプロセスがサブスクライバーへ転送します。そして、サブスクライバー内にある適用ワーカーがそのWALを適用します。

論理レプリケーションの流れにおいて、初回時とそれ以降で送信対象が異なります。初回時は、パブリッシャーの対象データのスナップショットを採取し、データを送信します(初期データ同期)。初回時以降、デコードされたWALを同期または非同期でサブスクライバーへ送信します。

レプリケーションの流れ

図4:レプリケーションの流れ

内部の仕組み

論理レプリケーションの内部の仕組みに関しては、以下の記事で解説しています。walsenderや適用ワーカーの内部動作に関して図を用いてわかりやすく説明していますので、内部の仕組みをさらに知りたい人は、ぜひお読みください。

構築可能な構成

論理レプリケーションで構築可能な構成、および構築不可能な構成について説明します。

N対Nとカスケードは可能

論理レプリケーションは、「テーブルに対してN対N」および「カスケード」の構成で構築できます。

N対Nの構成

図5:N対Nの構成

カスケード構成

図6:カスケード構成

パブリケーションは、「1テーブルに対して複数のパブリケーション」、「複数テーブルに対して1パブリケーション」、「複数スキーマに対して1パブリケーション」のようにレプリケーション対象のテーブルを指定できます。

パブリケーションと対象テーブルの関係

図7:パブリケーションと対象テーブルの関係

サブスクリプションは、1つあるいは複数のパブリケーションへの接続情報を指定するだけであるため、対象テーブルは接続するパブリケーションに依存します。

サブスクリプションと対象テーブルの関係

図8:サブスクリプションと対象テーブルの関係

双方向は不可

一方で、現時点の論理レプリケーションでは、「双方向(マルチマスタ)」および「ループ」の構成で構築できません。

双方向/ループ構成係

図9:双方向/ループ構成

また、複数のサブスクリプションから、同一のテーブルへレプリケーションすることができません。

サブスクリプションを設定できないパターン

図10:サブスクリプションを設定できないパターン

3. 設定方法と基本的な使い方

論理レプリケーションを使い、テーブル単位やスキーマ単位をレプリケーションする方法について順を追って、見ていきましょう。なお、今回はPostgreSQL 15で設定方法を説明します。

設定手順

シンプルな構成、かつ、簡単なサンプルを使用して論理レプリケーションを使ってみましょう。サンプルで使用するデータベースは「postgres」とします。以下の構成で論理レプリケーションを設定します。

設定する論理レプリケーションの環境

図11:設定する論理レプリケーションの環境

上記の環境を想定として、以降で以下の手順を説明します。

  • 1. パブリッシャー側の設定
  • 2. サブスクライバー側の設定
  • 3. 動作確認

1. パブリッシャー側の設定

  1. まずは、postgresql.confファイルのwal_levelを「logical」に変更します。

wal_level = 'logical'
  1. 次に、サブスクライバーがパブリッシャーに接続できるようにpg_hba.confを設定します。
    今回は、検証のため以下のように「全許可」かつ「パスワードなし」を設定します。

host    all             all             0.0.0.0/0            trust
  1. 続いて、レプリケーション用のテーブルとデータを作成しましょう。
    本検証では、以下のコマンドを実行しテーブルとデータを作成します。

postgres=# CREATE TABLE tbl(id INTEGER PRIMARY KEY, data TEXT);
postgres=# INSERT INTO tbl VALUES(1, 'TOKYO'),(2, 'OSAKA'),(3, 'NAGOYA'),(4, 'SHIZUOKA'),(5, 'KANAGAWA');
  1. 次に、パブリケーションを作成するために以下のコマンドを実行してください。

postgres=# CREATE PUBLICATION pub FOR TABLE tbl;

作成したパブリケーションは、以下のいずれかのコマンドで確認できます。


postgres=# SELECT * FROM pg_publication;
postgres=# \dRp
postgres=# SELECT * FROM pg_publication_tables;
  1. 最後に、レプリケーション用のロール作成とレプリケーション対象のテーブルに対してSELECT権限を付与してください。
    本検証では、「logi_repl_user」というロールを以下のコマンドで作成し権限を付与します。

postgres=# CREATE ROLE logi_repl_user LOGIN REPLICATION PASSWORD 'logi_repl_user';
postgres=# GRANT SELECT ON tbl TO logi_repl_user;

参考

対象テーブルへのSELECT権限を付与しなかった場合、サーバーログに以下のエラーが出力され、初期データ同期が行われません。


ERROR:  could not start initial contents copy for table "public.tbl": ERROR:  permission denied for table tbl4

2. サブスクライバー側の設定

  1. まずは、以下のようにサブスクリプション用のテーブルを作成しましょう。

postgres=# CREATE TABLE tbl(id INTEGER PRIMARY KEY, data TEXT);
  1. 次に、サブスクリプションを作成するために以下のコマンドを実行してください。

postgres=# CREATE SUBSCRIPTION sub CONNECTION 'host=node001 port=5432 user=logi_repl_user dbname=postgres' PUBLICATION pub;

参考

サブスクリプションを作成する前に対象テーブルを作成していない場合、以下のエラーが発生します。


ERROR:  relation "public.tbl" does not exist

サブスクリプションを作成すると、最初に初期データ同期が行われます。作成したサブスクリプションは、以下のいずれかのコマンドで確認できます。pg_subscriptionおよびpg_stat_subscriptionを使った確認方法に関しては、「状態を確認」を参照してください。


postgres=# SELECT * FROM pg_subscription;
postgres=# \dRs
postgres=# SELECT * FROM pg_stat_subscription;
postgres=# SELECT * FROM pg_subscription_rel;

3. 動作確認

  1. 論理レプリケーションの動作を確認するために、パブリッシャー側で以下のようにデータを追加しましょう。

postgres=# INSERT INTO tbl VALUES (6, 'HYOGO');
  1. 実行後、サブスクライバー側でデータが追加されているかを確認するために、以下のコマンドを実行してください。

postgres=# SELECT * FROM tbl;
id  |   data
----+----------
  1 | TOKYO
  2 | OSAKA
  3 | NAGOYA
  4 | SHIZUOKA
  5 | KANAGAWA
  6 | HYOGO

パブリッシャー側で追加したデータがサブスクライバー側に存在する場合、論理レプリケーションを設定できたと判断できます。

状態を確認

サブスクライバー側で以下のコマンドを実行し、システムカタログpg_subscriptionのsubenabledがfである場合、サブスクリプションが無効な状態であることを把握できます。

postgres=# SELECT subname, subenabled FROM pg_subscription;
-[ RECORD 1 ]----+-----------------------------------------------------------
subname           | sub
subenabled       | f

また、サブスクライバー側で以下のコマンドを実行し、システムカタログpg_stat_subscriptionのpidが空、received_lsnが空である場合、サブスクリプションが無効な状態であることを把握できます。

postgres=# SELECT subname, pid, received_lsn FROM pg_stat_subscription;
-[ RECORD 1 ]---------+------
subname               | sub
pid                   | 
received_lsn         | 

レプリケーションの停止と再開

サブスクライバー側でサブスクリプションを無効化することで、論理レプリケーションを停止できます。以下のコマンドをサブスクライバー側で実行することで、サブスクリプションを無効化できます。

ただし、運用中に一時停止すると、その間はパブリッシャー側でWALが溜まります。再開時には停止時点からレプリケーションが再開されるため、データ同期までに時間がかかります。

postgres=# ALTER SUBSCRIPTION sub DISABLE;

論理レプリケーションを再開したい場合、サブスクライバー側でサブスクリプションを有効化しましょう。以下のコマンドをサブスクライバー側で実行することで、サブスクリプションを有効化できます。確認方法に関しては、「状態を確認」を参照してください。

postgres=# ALTER SUBSCRIPTION sub ENABLE;

不足しているテーブル情報をパブリッシャーから取得

論理レプリケーションをすべてのテーブルを対象に設定した後(パブリッシャー作成時にFOR ALL TABLESを指定した場合など)に、パブリケーションにテーブルを追加、または、パブリケーションからテーブルを削除した場合、自動でサブスクライバー側に伝わりません。そのため、サブスクライバー側で以下のREFRESH PUBLICATIONの実行が必要です。実行することで、パブリッシャーからテーブルの情報を読み直し、追加されたテーブルのレプリケーションなどが行われるようになります。ちなみに、パブリケーションにテーブルを追加した場合、サブスクライバー側に追加したテーブルを手動で作成する必要があります。

postgres=# ALTER SUBSCRIPTION <サブスクリプション名> REFRESH PUBLICATION;

REFRESH実行の必要性

図12:REFRESH実行の必要性

フィルター機能

論理レプリケーションにはフィルター機能があります。フィルター機能を使うことで、指定した条件を満たすデータのみレプリケーションされるよう制限できます。
フィルター機能の種類として、列フィルター、行フィルター、スキーマフィルターがあります。以降で、各フィルターの機能概要と設定方法に関して説明します。

列フィルター

列フィルターの機能概要と設定方法については、以下の記事で解説しています。図やコマンド例を用いてわかりやすく説明していますので、ぜひお読みください。

行フィルター

行フィルターの機能概要と設定方法については、以下の記事で解説しています。図やコマンド例を用いてわかりやすく説明していますので、ぜひお読みください。

スキーマフィルター

スキーマフィルターの機能概要と設定方法については、以下の記事で解説しています。図やコマンド例を用いてわかりやすく説明していますので、ぜひお読みください。

4. 利用時に注意するべきポイント

論理レプリケーション機能を利用する場合に注意するべき5つのポイントに関して説明します。

パブリケーション

パブリケーションを定義する場合、以下の注意が必要です。

  • パブリケーションは1つのデータベース内の1つ以上のテーブルを対象として定義すること
  • パブリケーションで行フィルターや列フィルターの指定およびUPDATE文とDELETE文を実行する場合、レプリカアイデンティティが必須

サブスクリプション

サブスクリプションを定義する場合、以下の注意が必要です。

  • サブスクリプションは他のデータベースへの接続と、サブスクリプション対象の1つ以上のパブリケーションの集合を定義すること
  • サブスクリプションを作成する際に、あらかじめ複製先テーブルの作成が必要
  • レプリケーション用のユーザーには、REPLICATION属性、LOGIN属性設定、および、対象テーブルへのSELECT権限が必要。さらに、スキーマを指定する場合は、対象スキーマへのUSAGE権限が必要

レプリケーション対象のテーブル

論理レプリケーションを利用する場合、パブリッシャーとサブスクライバーの間ではテーブル照合が実施されます。テーブル照合は、完全修飾されたテーブル名(例:スキーマ名.テーブル名)に基づいて行われます。このため、パブリッシャーとサブスクライバー間で異なる名前になっているテーブルに対してレプリケーションはできません。
その他に押さえておくべきテーブル観点のポイントを以下にまとめます。

  • サブスクライバー側でレコードを格納する際、パブリッシャーから転送されないカラムの値は、カラム定義に従ってデフォルト値(指定が無い場合はNULL)が挿入される
  • パブリッシャーとサブスクライバー間でテーブルのカラム名が一致していること
  • パブリッシャーとサブスクライバー間でテーブルのカラムの順序は一致している必要はない
  • サブスクライバー側で定義するテーブルは、パブリッシャー側のテーブルに無いカラムが存在してもよく、また、パブリッシャー側のテーブル内のすべてのカラムを指定する必要もない
  • カラムのデータ型は、PostgreSQL内部で変換可能である限り一致している必要はない
  • レプリケーション中でもカラム追加や削除は可能。例えば、パブリッシャー側で1カラム削除した場合、サブスクライバー側へ正しくレプリケーションができる(削除したカラムにはNULL値が格納)

レプリケーションスロット

論理レプリケーションでのデータ送信の記録には、レプリケーションスロットを使用します。障害からの復旧をする上でデータ送信の記録は重要です。サブスクリプションを作成すると自動的にレプリケーションスロットがパブリケーション側に作成されます。任意の名称でレプリケーションスロットを作成したい場合、サブスクリプション作成時のパラメータで指定してください。

UPDATE文とDELETE文のレプリケーション

UPDATE文とDELETE文を論理レプリケーションでレプリケーションするためには、利用するカラムにレプリカアイデンティティ(主キー、ユニークキー)の指定が必要です。

参考

利用するカラムにレプリカアイデンティティを指定せずに、UPDETE文やDELETE文を実行すると以下のエラーが発生します。


postgres=# UPDATE tbl SET area = 4000.0 WHERE id = 1;
ERROR:  cannot update table "tbl"
DETAIL:  Column used in the publication WHERE expression is not part of the replica identity.
postgres=# DELETE FROM tbl;
ERROR:  cannot delete from table "tbl" because it does not have a replica identity and publishes deletes
HINT:  To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE.

ALTER TABLEで該当カラムにレプリカアイデンティティを指定することで上記エラーを解消できます。


ここまで説明してきましたが、論理レプリケーションは比較的簡単な手順で利用できることがおわかりいただけたと思います。注意事項に気を付けて、業務要件に合わせてご利用をご検討ください。

なお、論理レプリケーションには、冗長化の範囲がテーブル内のデータのみで、可用性全般を担保する機構がありません。そのため、実際の業務においては、ストリーミングレプリケーションと論理レプリケーションを併用するケースが多いと考えられます。併用理由やフェイルオーバー時の復旧方法については、「論理レプリケーションの復旧方法 ~ ストリーミングレプリケーションのフェイルオーバー併用時 ~」を参照してください。

2023年2月8日公開

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ