PostgreSQLには2種類のレプリケーションがあります。ストリーミングレプリケーション(物理レプリケーション)はデータベース全体を丸ごとコピーします。一方、論理レプリケーション(Logical Replication)はテーブル単位で同期範囲を選べます。バージョンが異なるサーバー間でも動きますし、PostgreSQL 10から正式機能として使えます。
この記事では Ubuntu 24.04 LTS + PostgreSQL 16.14 を使い、2つのDockerコンテナ(Publisher・Subscriber)を立てて実際に論理レプリケーションを動かしました。INSERT/UPDATEがリアルタイムで同期されることを自分の手で確認できます。
この記事のポイント
- Ubuntu 24.04 + PostgreSQL 16.14 で動作確認(
docker run ubuntu:24.04実測) - 設定のキーは
wal_level = logical(デフォルトはreplicaなので変更が必要) CREATE PUBLICATION(送信側)とCREATE SUBSCRIPTION(受信側)の2コマンドで完成- テーブル単位の指定が可能——全テーブルではなく特定テーブルだけを同期できる
pg_stat_replicationとpg_stat_subscriptionで同期状態をリアルタイム確認
目次
- 論理レプリケーションとは(ストリーミングとの違い)
- 前提環境と構成
- PostgreSQL のインストールと初期確認
- Publisher の設定(wal_level・pg_hba.conf)
- テスト用テーブルと PUBLICATION の作成
- Subscriber の設定と SUBSCRIPTION の作成
- 同期動作の確認(INSERT/UPDATE のリアルタイム反映)
- pg_stat_replication で状態を確認する
- よくあるエラーと対処
- まとめ
論理レプリケーションとは
PostgreSQL には大きく2種類のレプリケーションがあります。
| 方式 | 同期範囲 | バージョン差 | 主な用途 |
|---|---|---|---|
| ストリーミング(物理) | クラスタ全体 | 同一バージョン必須 | HA・障害復旧 |
| 論理レプリケーション | テーブル単位で選択可 | バージョン差OK(PG10以上) | 部分同期・バージョンアップ移行 |
論理レプリケーションが便利なのは、異なるメジャーバージョン間で動く点です。たとえば PostgreSQL 14 から 16 にアップグレードするとき、古いサーバーから新しいサーバーへ「止めずに」データを移せます。バージョンアップの際に読者がよく困るのがダウンタイムですが、論理レプリケーションを使うと最小限に抑えられます。
前提環境と構成
今回の検証環境は次のとおりです。
動作確認環境
Ubuntu 24.04 LTS(Docker公式イメージ ubuntu:24.04)で実行。PostgreSQL 16.14(apt install postgresql でインストール)。Publisher と Subscriber を別コンテナで動かし、Dockerネットワーク経由で接続しています。
構成はシンプルです:
└── products テーブルに PUBLICATION を設定
│ wal_level=logical で WAL を論理デコード
↓
Subscriber (Ubuntu 24.04 / PostgreSQL 16)
└── SUBSCRIPTION で Publisher に接続・同期
VPS 上での本番構成でも考え方は同じです。Publisher がメインサーバー、Subscriber がレプリカサーバーになります。
PostgreSQL のインストールと初期確認
Ubuntu 24.04 の公式リポジトリには PostgreSQL 16 が収録されています。1コマンドでインストールできます。

Setting up postgresql-16 (16.14-0ubuntu0.24.04.1) …
Creating new PostgreSQL cluster 16/main …
Setting up postgresql (16+257build1.1) …
$ psql –version
psql (PostgreSQL) 16.14 (Ubuntu 16.14-0ubuntu0.24.04.1)
インストール直後にクラスタが自動作成され、PostgreSQL 16 がポート 5432 で起動します。pg_lsclusters で状態を確認できます。
Ver Cluster Port Status Owner Data directory Log file
16 main 5432 online postgres /var/lib/postgresql/16/main /var/log/…
Ubuntu のバージョン別に収録される PostgreSQL のバージョンが異なります。

Ubuntu 20.04 はすでに EOL(延長サポート終了)です。新規構築するなら Ubuntu 24.04 LTS + PostgreSQL 16 一択です。
Publisher の設定(wal_level・pg_hba.conf)
論理レプリケーションを使うには、Publisher 側で3つの変更が必要です。
手順1:wal_level を logical に変更する
デフォルトの wal_level は replica です。論理デコードには logical が必要で、ALTER SYSTEM で変更します。

— 現在の設定を確認
postgres=# SHOW wal_level;
wal_level
———–
replica
— logical に変更(postgresql.auto.conf に書き込まれる)
postgres=# ALTER SYSTEM SET wal_level = logical;
ALTER SYSTEM
postgres=# ALTER SYSTEM SET max_replication_slots = 10;
ALTER SYSTEM
postgres=# ALTER SYSTEM SET max_wal_senders = 10;
ALTER SYSTEM
postgres=# ALTER SYSTEM SET listen_addresses = ‘*’;
ALTER SYSTEM
ALTER SYSTEM は postgresql.auto.conf に設定を書き込みます。postgresql.conf を直接編集するより安全で、設定の来歴が追いやすくなります。
手順2:pg_hba.conf でレプリケーション接続を許可する
Subscriber からの接続を許可するため、pg_hba.conf に行を追加します。
— 末尾に追加(CIDR は実環境のSubnet に合わせる)
host replication all 10.0.0.0/8 scram-sha-256
host all all 10.0.0.0/8 scram-sha-256
注意:本番環境でのCIDR設定
検証では 0.0.0.0/0(全接続許可)を使いましたが、本番では Subscriber の IP レンジだけに絞ってください。trust 認証も本番では使わず、scram-sha-256 にすること。
手順3:PostgreSQL を再起動する
$ sudo -u postgres psql -c “SHOW wal_level;”
logical
logical が返れば準備完了です。この確認を飛ばすと、あとで CREATE PUBLICATION がエラーになるので必ず実行しておきます。
テスト用テーブルと PUBLICATION の作成
Publisher 側でテストデータベースとテーブルを作り、PUBLICATION を設定します。
$ sudo -u postgres psql -d testdb
— テーブル作成
testdb=# CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
price NUMERIC(10,2)
);
CREATE TABLE
— テストデータを投入
testdb=# INSERT INTO products (name, price)
VALUES (‘Ubuntu Pro’, 0), (‘PostgreSQL’, 0), (‘pgbouncer’, 0);
INSERT 0 3
手順4:PUBLICATION を作成する
CREATE PUBLICATION でこのテーブルを公開します。

testdb=# CREATE PUBLICATION products_pub FOR TABLE products;
CREATE PUBLICATION
— 確認:INSERT/UPDATE/DELETE すべて有効(デフォルト)
testdb=# SELECT pubname, pubinsert, pubupdate, pubdelete FROM pg_publication;
pubname | pubinsert | pubupdate | pubdelete
————–+———–+———–+———–
products_pub | t | t | t
全テーブルを公開したい場合は FOR TABLE の代わりに FOR ALL TABLES と書きます。今回のようにテーブルを絞る方が、不要なデータが流れないため本番では推奨です。
Subscriber の設定と SUBSCRIPTION の作成
Subscriber 側(別サーバーまたは別コンテナ)で PostgreSQL を起動し、同じテーブル定義のみ先に作成します。
$ sudo -u postgres psql -d testdb
— Subscriber 側にも同じスキーマを作成(データは空でよい)
testdb=# CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
price NUMERIC(10,2)
);
CREATE TABLE
手順5:SUBSCRIPTION を作成する
Publisher の接続情報を指定して SUBSCRIPTION を作成します。
CONNECTION ‘host=Publisher_IP port=5432 dbname=testdb
user=postgres password=パスワード‘
PUBLICATION products_pub;
NOTICE: created replication slot “products_sub” on publisher
CREATE SUBSCRIPTION
NOTICE メッセージで Publisher 側に Replication Slot が自動作成されたことを確認できます。これが成功すれば、Publisher の既存データが即座に Subscriber に流れます。
testdb=# SELECT subname, subenabled, subslotname FROM pg_subscription;
subname | subenabled | subslotname
————–+————+————–
products_sub | t | products_sub
— 既存データが同期されているか確認
testdb=# SELECT * FROM products;
id | name | price
—-+————+——-
1 | Ubuntu Pro | 0.00
2 | PostgreSQL | 0.00
3 | pgbouncer | 0.00
(3 rows)
3行が表示されれば初期同期は完了です。
同期動作の確認(INSERT/UPDATE のリアルタイム反映)
Publisher 側でデータを変更し、Subscriber 側に即時反映されることを確認します。

testdb=# INSERT INTO products (name, price) VALUES (‘Linux Kernel’, 5.99);
INSERT 0 1
testdb=# UPDATE products SET price=9.99 WHERE name=’Ubuntu Pro’;
UPDATE 1
数秒後(場合によっては即座に)、Subscriber 側に反映されます。

testdb=# SELECT * FROM products ORDER BY id;
id | name | price
—-+————–+——-
1 | Ubuntu Pro | 9.99
2 | PostgreSQL | 0.00
3 | pgbouncer | 0.00
4 | Linux Kernel | 5.99
(4 rows)
私が実測したとき、INSERT/UPDATE は数秒以内(多くは1秒未満)でSubscriberに届いていました。ネットワーク遅延が支配的で、PostgreSQL 側の処理コストはほぼ無視できる範囲です。
pg_stat_replication で状態を確認する
レプリケーションが正常に動いているかは pg_stat_replication(Publisher側)と pg_stat_subscription(Subscriber側)で確認できます。

“SELECT application_name, client_addr, state, sent_lsn, replay_lsn
FROM pg_stat_replication;”
-[ RECORD 1 ]—-+————-
application_name | products_sub
client_addr | 172.24.0.3
state | streaming
sent_lsn | 0/19862E8
replay_lsn | 0/19862E8
state=streaming かつ sent_lsn と replay_lsn が一致していれば、遅延ゼロで同期しています。
“SELECT slot_name, slot_type, active FROM pg_replication_slots;”
slot_name | slot_type | active
————–+———–+——–
products_sub | logical | t
slot_type=logical(論理スロット)で active=t になっています。Subscriber 側から確認するなら pg_stat_subscription です。
FROM pg_stat_subscription;
subname | received_lsn | latest_end_lsn
————–+————–+—————
products_sub | 0/19862E8 | 0/19862E8
よくあるエラーと対処
①「could not connect to the publisher」
Connection refused の場合は Publisher の listen_addresses が localhost のままです。
postgres=# ALTER SYSTEM SET listen_addresses = ‘*’;
ALTER SYSTEM
$ sudo pg_ctlcluster 16 main restart
②「fe_sendauth: no password supplied」
pg_hba.conf が scram-sha-256(パスワード認証)のとき、SUBSCRIPTION の CONNECTION 文字列にパスワードが必要です。
postgres=# ALTER USER postgres WITH PASSWORD ‘your_password’;
ALTER ROLE
③UPDATE が Subscriber に届かない
テーブルに PRIMARY KEY がないと UPDATE/DELETE はレプリケーションされません(デフォルトの REPLICA IDENTITY は DEFAULT=PRIMARY KEY 使用)。
testdb=# ALTER TABLE products REPLICA IDENTITY FULL;
ALTER TABLE
パフォーマンスへの注意
REPLICA IDENTITY FULL は更新ごとに全カラムを WAL に書くのでオーバーヘッドが大きくなります。PRIMARY KEY を付けるのが最善です。
④wal_level の変更が反映されない
ALTER SYSTEM 後に再起動を忘れると変更が反映されません。pg_ctlcluster 16 main restart(Ubuntu の場合)を実行してください。SELECT pg_reload_conf() では wal_level は変わりません。再起動が必要な設定です。
まとめ
PostgreSQL 論理レプリケーションの設定を Ubuntu 24.04 + PostgreSQL 16.14 で実測しました。
ALTER SYSTEM SET wal_level = logical→ PostgreSQL 再起動 の2ステップで有効化- Publisher 側は
CREATE PUBLICATION テーブル名、Subscriber 側はCREATE SUBSCRIPTION 接続文字列の1コマンドずつ - 同期状態は
pg_stat_replication(Publisher)とpg_stat_subscription(Subscriber)で確認できる - UPDATE/DELETE を使うテーブルには PRIMARY KEY を設定しておくこと
VPS 上で本番利用するなら、接続文字列のパスワードを直書きせず ~postgres/.pgpass に書く方法も調べておくと運用が楽になります。論理レプリケーションは PostgreSQL 14 → 16 のバージョンアップ移行にも使えます。ダウンタイムを最小化したい場合の選択肢の一つとして覚えておいてください。
VPS で PostgreSQL を本番運用するなら、まずサーバーを用意する必要があります。



コメント