PostgreSQLの論理レプリケーション(PUBLICATION・SUBSCRIPTION)をLinuxで設定する手順|テーブル単位の非同期複製と動作確認

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxtips > データーベース管理 > PostgreSQLの論理レプリケーション(PUBLICATION・SUBSCRIPTION)をLinuxで設定する手順|テーブル単位の非同期複製と動作確認
「論理レプリケーションとストリーミングレプリケーションの違いがよくわからない」「バージョン差のある2台で一部テーブルだけ同期したい」、こういった場面で役立つのがPostgreSQLの論理レプリケーションです。

PostgreSQL 10以降に正式実装された論理レプリケーションは、PUBLICATION(送信側)とSUBSCRIPTION(受信側)を使ってテーブル単位で非同期複製を行います。ストリーミングレプリケーション(物理)と異なり、バージョン差のある環境間でも動作するため、メジャーバージョンアップ時のダウンタイム最小化にも応用できます。

この記事では、RHEL 9系~Rocky Linux 9を想定環境として、PostgreSQL 16を使った論理レプリケーションの構築手順を解説します。wal_levelの設定変更からPUBLICATION・SUBSCRIPTIONの作成、動作確認、テーブル追加・削除時の対応、トラブルシュートまでを1本でまとめています。

この記事のポイント

・PUBLICATION(送信側)とSUBSCRIPTION(受信側)でテーブル単位に複製を制御できる
・postgresql.confのwal_levelを「logical」に変更しないとPUBLICATIONが作成できない
・pg_stat_replication / pg_stat_subscriptionで同期状態をリアルタイムに確認できる
・バージョン差のある2台でも動作するためメジャーバージョンアップのダウンタイム短縮にも活用できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

論理レプリケーションとストリーミングレプリケーション(物理)の違い

PostgreSQLのレプリケーションには「ストリーミングレプリケーション(物理)」と「論理レプリケーション」の2種類があります。どちらを選ぶかは用途によって異なります。
項目 ストリーミングレプリケーション(物理) 論理レプリケーション
複製単位 クラスター全体(全データベース・全テーブル) テーブル単位(指定したテーブルのみ)
バージョン差 不可(同一メジャーバージョンのみ) 可(受信側が送信側と同じかそれ以上のバージョン)
DDL(CREATE TABLE等) 自動複製される 自動複製されない(手動でスキーマを合わせる)
受信側への書き込み 不可(読み取り専用スタンバイ) 可(通常のテーブルとして書き込みもできる)
主な用途 HAフェイルオーバー、読み取りスケールアウト テーブル選択複製、バージョンアップ移行、データ集約
「一部テーブルだけ別サーバーにコピーしたい」「バージョンアップ時に並走させてダウンタイムを削減したい」という用途であれば、論理レプリケーションが適しています。物理レプリケーションはサーバー全体をホットスタンバイとして使い、フェイルオーバーや読み取り負荷分散を目的とする場合に向いています。

構築前の確認とwal_levelの設定

論理レプリケーションを有効にするには、パブリッシャー(送信側)のpostgresql.confでwal_level = logicalを設定する必要があります。デフォルト値はreplicaで、このままではPUBLICATIONを作成できません。

今回の構成は以下の通りです。
役割 IPアドレス(例) 説明
パブリッシャー(Publisher) 192.168.1.10 データの送信側。PUBLICATIONを作成するサーバー
サブスクライバー(Subscriber) 192.168.1.20 データの受信側。SUBSCRIPTIONを作成するサーバー

1. 現在のwal_levelを確認する

パブリッシャーでpsqlを起動し、現在の設定を確認します。

# パブリッシャーサーバーで実行 sudo -u postgres psql -c "SHOW wal_level;"

出力例(環境により異なります):

wal_level ----------- replica (1 row)

replicaと表示された場合は変更が必要です。すでにlogicalであれば「2. PUBLICATIONの作成」まで読み飛ばしてください。

2. postgresql.confでwal_levelをlogicalに変更する

postgresql.confを編集します。RHEL系では/var/lib/pgsql/16/data/postgresql.conf、Debian/Ubuntu系では/etc/postgresql/16/main/postgresql.confが標準のパスです。

# RHEL 9系・Rocky Linux 9の例 sudo vi /var/lib/pgsql/16/data/postgresql.conf

以下の行を見つけて変更します。

# 変更前(コメントアウトされていることが多い) #wal_level = replica # 変更後 wal_level = logical

3. max_wal_sendersとmax_replication_slotsを確認する

論理レプリケーションはレプリケーションスロットを使うため、max_wal_sendersとmax_replication_slotsにも余裕が必要です。PostgreSQL 16のデフォルトは10で、通常はそのままで問題ありません。

sudo -u postgres psql -c "SHOW max_wal_senders; SHOW max_replication_slots;"

0になっている場合は最低でも10に増やしてください。変更後はPostgreSQLを再起動します。

# RHEL 9系・Rocky Linux 9 sudo systemctl restart postgresql-16 # Ubuntu 24.04の場合 sudo systemctl restart postgresql

再起動後にwal_levelがlogicalになっていることを確認します。

sudo -u postgres psql -c "SHOW wal_level;"

出力例(環境により異なります):

wal_level ----------- logical (1 row)

パブリッシャー側の設定

wal_levelの変更が完了したら、送信側(パブリッシャー)の設定を行います。

1. レプリケーション用ロールを作成する

PUBLICATIONを利用するには、サブスクライバーがパブリッシャーへ接続するためのロール(ユーザー)が必要です。このロールにはREPLICATION属性とテーブルへのSELECT権限が必要です。

sudo -u postgres psql

psql接続後、以下を実行します。パスワードは環境に合わせて設定してください。

-- レプリケーション用ロールの作成 CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'パスワード'; -- 対象データベースへのCONNECT権限を付与 GRANT CONNECT ON DATABASE mydb TO replicator; -- 対象スキーマ内の全テーブルへSELECT権限を付与 \c mydb GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator;

2. pg_hba.confで接続を許可する

サブスクライバーのIPアドレスからの接続を許可します。pg_hba.confに以下の2行を追加します。

sudo vi /var/lib/pgsql/16/data/pg_hba.conf

# レプリケーション接続(WAL送信用) host replication replicator 192.168.1.20/32 scram-sha-256 # 通常DB接続(SUBSCRIPTION作成時のメタデータ取得用) host mydb replicator 192.168.1.20/32 scram-sha-256

編集後、設定を再読み込みします。

sudo -u postgres psql -c "SELECT pg_reload_conf();"

なお、パブリッシャーとサブスクライバー間にファイアウォールがある場合は、5432/tcpポートへの通信を許可してください。Linux ポート確認の全コマンドも合わせて参照してください。

3. PUBLICATIONを作成する

パブリッシャーの対象データベース(mydb)に接続し、PUBLICATIONを作成します。

sudo -u postgres psql -d mydb

-- 特定テーブルのみPUBLICATIONに含める場合 CREATE PUBLICATION mypub FOR TABLE orders, products; -- データベース内の全テーブルを含める場合 -- CREATE PUBLICATION mypub FOR ALL TABLES;

PUBLICATIONが作成されたことを確認します。

SELECT * FROM pg_publication;

出力例(環境により異なります):

pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubtruncate -----------+----------+--------------+-----------+-----------+-----------+------------- mypub | 10 | f | t | t | t | t (1 row)

pubinsert / pubupdate / pubdeleteがすべてtになっていれば、INSERT・UPDATE・DELETEが複製対象として有効です。

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

1. テーブルスキーマをあらかじめ作成する

論理レプリケーションはDDL(テーブル定義)を自動複製しません。サブスクライバー側にあらかじめ同じ構造のテーブルを作成しておく必要があります。パブリッシャーからスキーマのみをエクスポートする方法が確実です。

# パブリッシャーサーバーで実行 — スキーマのみエクスポート(データは除外) pg_dump -U postgres -d mydb --schema-only -t orders -t products > mydb_schema.sql

エクスポートしたSQLをサブスクライバーへ転送し、インポートします。

# サブスクライバーサーバーで実行 scp user@192.168.1.10:/path/to/mydb_schema.sql ./ # データベースの作成(存在しない場合) sudo -u postgres createdb mydb # スキーマのインポート sudo -u postgres psql -d mydb < mydb_schema.sql

2. SUBSCRIPTIONを作成する

サブスクライバーのデータベースに接続し、SUBSCRIPTIONを作成します。

sudo -u postgres psql -d mydb

CREATE SUBSCRIPTION mysub CONNECTION 'host=192.168.1.10 port=5432 dbname=mydb user=replicator password=パスワード' PUBLICATION mypub;

SUBSCRIPTIONを作成すると、パブリッシャー側にレプリケーションスロットが自動で作成され、初期データの同期(initial snapshot)が始まります。テーブルにデータが大量にある場合、初期同期に時間がかかるため注意してください。

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

1. パブリッシャー側でpg_stat_replicationを確認する

sudo -u postgres psql -d mydb -c "SELECT pid, usename, application_name, client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, sync_state FROM pg_stat_replication;"

出力例(環境により異なります):

pid | usename | application_name | client_addr | state | sent_lsn | replay_lsn | sync_state -------+-----------+------------------+--------------+-----------+-----------+------------+----------- 3421 | replicator| mysub | 192.168.1.20 | streaming | 0/1A00028 | 0/1A00028 | async (1 row)

state = streamingになっていれば正常に同期中です。sent_lsnとreplay_lsnが一致していれば遅延がないことを示します。

2. サブスクライバー側でpg_stat_subscriptionを確認する

sudo -u postgres psql -d mydb -c "SELECT subid, subname, pid, received_lsn, last_msg_receipt_time, latest_end_lsn FROM pg_stat_subscription;"

出力例(環境により異なります):

subid | subname | pid | received_lsn | last_msg_receipt_time | latest_end_lsn -------+---------+------+--------------+-------------------------------+--------------- 16390 | mysub | 5234 | 0/1A00028 | 2026-10-21 14:00:00.123456+09 | 0/1A00028 (1 row)

3. テストデータで動作を確かめる

パブリッシャーでINSERTを実行し、サブスクライバーにデータが届くか確認します。

# パブリッシャーサーバーで実行 sudo -u postgres psql -d mydb -c "INSERT INTO orders (id, item, qty) VALUES (1, 'widget', 10);"

# サブスクライバーサーバーで確認 sudo -u postgres psql -d mydb -c "SELECT * FROM orders;"

出力例(環境により異なります):

id | item | qty ----+--------+----- 1 | widget | 10 (1 row)

サブスクライバーにデータが表示されれば論理レプリケーションは正常に動作しています。

テーブルの追加・削除とSUBSCRIPTIONの更新

運用中に複製対象のテーブルを変更したい場合は、PUBLICATIONとSUBSCRIPTIONの両方を更新する必要があります。

PUBLICATIONにテーブルを追加する

# パブリッシャーでPUBLICATIONにテーブルを追加 sudo -u postgres psql -d mydb -c "ALTER PUBLICATION mypub ADD TABLE customers;"

追加したテーブルのスキーマをサブスクライバーに先に作成した上で、SUBSCRIPTIONを更新してPUBLICATIONの変更を取り込みます。

# サブスクライバーでSUBSCRIPTIONを更新 sudo -u postgres psql -d mydb -c "ALTER SUBSCRIPTION mysub REFRESH PUBLICATION;"

PUBLICATIONからテーブルを削除する

# パブリッシャーでPUBLICATIONからテーブルを削除 sudo -u postgres psql -d mydb -c "ALTER PUBLICATION mypub DROP TABLE products;"

テーブルをPUBLICATIONから削除してもサブスクライバー側のテーブルは削除されません。以降の変更が届かなくなるだけです。サブスクライバー側でもALTER SUBSCRIPTION mysub REFRESH PUBLICATION;を実行してください。

SUBSCRIPTION・PUBLICATIONを削除する

# SUBSCRIPTIONを一時停止 sudo -u postgres psql -d mydb -c "ALTER SUBSCRIPTION mysub DISABLE;" # SUBSCRIPTIONを削除(レプリケーションスロットも自動解放される) sudo -u postgres psql -d mydb -c "DROP SUBSCRIPTION mysub;" # PUBLICATIONを削除(パブリッシャー側) sudo -u postgres psql -d mydb -c "DROP PUBLICATION mypub;"

SUBSCRIPTIONを削除せずにパブリッシャーを停止すると、レプリケーションスロットが残り続け、パブリッシャーのWALディスクが枯渇するリスクがあります。不要になった場合はサブスクライバーのSUBSCRIPTIONから先に削除してください。

トラブルシュートとよくあるエラー

「ERROR: publication "mypub" does not exist」

PUBLICATIONが存在しないままCREATE SUBSCRIPTIONを実行した時に発生します。パブリッシャー側でSELECT * FROM pg_publication;を実行してPUBLICATIONの存在を確認してください。

「FATAL: no pg_hba.conf entry for replication connection」

pg_hba.confのreplicationコンテキスト行が不足しているか、サブスクライバーのIPアドレスが一致していません。追加後にSELECT pg_reload_conf();で設定を再読み込みしてください。

「ERROR: logical replication slot "mysub" already exists」

過去に削除したSUBSCRIPTIONのレプリケーションスロットが残った状態で、同名のSUBSCRIPTIONを再作成しようとした時に発生します。パブリッシャー側で古いスロットを削除します。

# パブリッシャーで実行 — スロット名はサブスクリプション名と同一 sudo -u postgres psql -c "SELECT pg_drop_replication_slot('mysub');"

レプリケーション遅延(lag)が大きい

パブリッシャーへの書き込み量が多い場合やネットワーク帯域が不足している場合に遅延が発生します。パブリッシャー側で遅延バイト数を確認します。

sudo -u postgres psql -c " SELECT application_name, (sent_lsn - replay_lsn) AS lag_bytes, now() - pg_last_xact_replay_timestamp() AS lag_time FROM pg_stat_replication; "

lag_bytesが継続して増加している場合は、サブスクライバーのI/O性能やCPUリソースを確認してください。

「could not connect to the publisher」

接続文字列のhost・port・dbname・user・passwordの誤りのほか、サブスクライバーからパブリッシャーへのファイアウォール設定(5432/tcpポート)が原因になることが多いです。まず接続文字列を確認し、次にネットワーク経路を確認してください。

本記事のまとめ

PostgreSQLの論理レプリケーション(PUBLICATION・SUBSCRIPTION)の設定手順をまとめます。
手順 対象 設定内容
wal_levelをlogicalに変更 パブリッシャー wal_level = logical(postgresql.conf)
レプリケーション用ロール作成 パブリッシャー CREATE ROLE replicator WITH REPLICATION LOGIN ...
pg_hba.confへの接続許可追加 パブリッシャー host replication replicator <IP> scram-sha-256
PUBLICATIONの作成 パブリッシャー CREATE PUBLICATION mypub FOR TABLE ...
テーブルスキーマの作成 サブスクライバー pg_dump --schema-onlyでエクスポート後インポート
SUBSCRIPTIONの作成 サブスクライバー CREATE SUBSCRIPTION mysub CONNECTION '...' PUBLICATION mypub
動作確認 両サーバー pg_stat_replication / pg_stat_subscription
論理レプリケーションはメジャーバージョンアップ時のダウンタイム最小化にも活用できます。旧バージョンのパブリッシャーと新バージョンのサブスクライバーを並走させ、切り替えタイミングでSUBSCRIPTIONを停止して接続先を変更するという運用です。本番環境への適用前には必ず検証環境でリハーサルを行ってください。

Linuxサーバー上でのPostgreSQL運用をさらに深めたい方は、Linuxサーバー構築・運用の実践セミナーも参考にしてみてください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の実務経験を持つ講師が2日間のハンズオンで、PostgreSQLを含むLinuxサーバー運用の要点を直接指導します。詳細は下記からご確認ください。
>> Linux Master Pro Seminarの詳細を見る

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。