PostgreSQL論理レプリケーション on Ubuntu — テーブル単位の同期設定

データベース

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_replicationpg_stat_subscription で同期状態をリアルタイム確認

目次

  1. 論理レプリケーションとは(ストリーミングとの違い)
  2. 前提環境と構成
  3. PostgreSQL のインストールと初期確認
  4. Publisher の設定(wal_level・pg_hba.conf)
  5. テスト用テーブルと PUBLICATION の作成
  6. Subscriber の設定と SUBSCRIPTION の作成
  7. 同期動作の確認(INSERT/UPDATE のリアルタイム反映)
  8. pg_stat_replication で状態を確認する
  9. よくあるエラーと対処
  10. まとめ

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

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ネットワーク経由で接続しています。

構成はシンプルです:




構成図(2コンテナ)
Publisher (Ubuntu 24.04 / PostgreSQL 16)
└── products テーブルに PUBLICATION を設定
│ wal_level=logical で WAL を論理デコード

Subscriber (Ubuntu 24.04 / PostgreSQL 16)
└── SUBSCRIPTION で Publisher に接続・同期

VPS 上での本番構成でも考え方は同じです。Publisher がメインサーバー、Subscriber がレプリカサーバーになります。

PostgreSQL のインストールと初期確認

Ubuntu 24.04 の公式リポジトリには PostgreSQL 16 が収録されています。1コマンドでインストールできます。

apt install postgresql 実ログ(Ubuntu 24.04 LTS / 実測)
apt install postgresql 実ログ(Ubuntu 24.04 LTS / 実測)



ubuntu@server: ~
$ sudo apt update && sudo apt install -y postgresql
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 で状態を確認できます。




ubuntu@server: ~
$ 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 バージョン別 PostgreSQL バージョン比較(実測)
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_levelreplica です。論理デコードには logical が必要で、ALTER SYSTEM で変更します。

wal_level を logical に変更(PostgreSQL 16 実測)
wal_level を logical に変更(PostgreSQL 16 実測)



ubuntu@publisher: ~
$ sudo -u postgres psql
— 現在の設定を確認
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 SYSTEMpostgresql.auto.conf に設定を書き込みます。postgresql.conf を直接編集するより安全で、設定の来歴が追いやすくなります。

手順2:pg_hba.conf でレプリケーション接続を許可する

Subscriber からの接続を許可するため、pg_hba.conf に行を追加します。




ubuntu@publisher: ~
$ sudo nano /etc/postgresql/16/main/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 を再起動する




ubuntu@publisher: ~
$ sudo pg_ctlcluster 16 main restart
$ sudo -u postgres psql -c “SHOW wal_level;”
logical

logical が返れば準備完了です。この確認を飛ばすと、あとで CREATE PUBLICATION がエラーになるので必ず実行しておきます。

テスト用テーブルと PUBLICATION の作成

Publisher 側でテストデータベースとテーブルを作り、PUBLICATION を設定します。




ubuntu@publisher: ~
$ sudo -u postgres createdb testdb
$ 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 でこのテーブルを公開します。

PUBLICATION / SUBSCRIPTION 作成と確認(PostgreSQL 16 実測)
PUBLICATION / SUBSCRIPTION 作成と確認(PostgreSQL 16 実測)



ubuntu@publisher: testdb
— テーブルを指定して 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 を起動し、同じテーブル定義のみ先に作成します。




ubuntu@subscriber: ~
$ sudo -u postgres createdb testdb
$ sudo -u postgres psql -d testdb

— Subscriber 側にも同じスキーマを作成(データは空でよい)
testdb=# CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
price NUMERIC(10,2)
);
CREATE TABLE

スキーマは事前に作っておく必要があります。CREATE SUBSCRIPTION は既存のテーブルへデータを流し込むだけで、テーブルの作成はしません。ここで詰まる人が多いので注意です。

手順5:SUBSCRIPTION を作成する

Publisher の接続情報を指定して SUBSCRIPTION を作成します。




ubuntu@subscriber: testdb
testdb=# CREATE SUBSCRIPTION products_sub
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 に流れます。




ubuntu@subscriber: testdb
— SUBSCRIPTION の状態確認
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 側に即時反映されることを確認します。

Publisher 側での PUBLICATION 確認と INSERT 後のデータ(実撮影)
Publisher 側での PUBLICATION 確認と INSERT 後のデータ(実撮影)



ubuntu@publisher: testdb
— Publisher 側でレコード追加・更新
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 側に反映されます。

Subscriber 側で INSERT/UPDATE が反映された確認(実撮影)
Subscriber 側で INSERT/UPDATE が反映された確認(実撮影)



ubuntu@subscriber: testdb
— Subscriber 側で確認(Publisher の変更が反映されているか)
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側)で確認できます。

pg_stat_replication でレプリケーション状態確認(PostgreSQL 16 実測)
pg_stat_replication でレプリケーション状態確認(PostgreSQL 16 実測)



ubuntu@publisher: postgres
$ sudo -u postgres psql -x -c \
“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_lsnreplay_lsn が一致していれば、遅延ゼロで同期しています。




ubuntu@publisher: postgres(Replication Slot確認)
$ sudo -u postgres psql -c \
“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 です。




ubuntu@subscriber: testdb
testdb=# SELECT subname, received_lsn, latest_end_lsn
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_addresseslocalhost のままです。




ubuntu@publisher: postgres
— 外部からの接続を受け付けるように変更
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 文字列にパスワードが必要です。




ubuntu@publisher: postgres
— replication 用ロールにパスワードを設定
postgres=# ALTER USER postgres WITH PASSWORD ‘your_password’;
ALTER ROLE

③UPDATE が Subscriber に届かない

テーブルに PRIMARY KEY がないと UPDATE/DELETE はレプリケーションされません(デフォルトの REPLICA IDENTITYDEFAULT=PRIMARY KEY 使用)。




ubuntu@publisher: testdb
— PRIMARY KEY がない場合は FULL モードを使う(全カラムが識別子になる)
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 を本番運用するなら、まずサーバーを用意する必要があります。

Ubuntuサーバー構築の手順 VPSで実際に立てて解説
「VPS を借りたけど、Ubuntu サーバーをどう設定すればいいか分からない」——そんな疑問に、実際に Ubuntu 24.04 LTS 上でコマンドを動かして確認した手順でお答えします。

コメント

タイトルとURLをコピーしました