PostgreSQLのストリーミングレプリケーションは、WAL(Write-Ahead Log)をプライマリからスタンバイへリアルタイムで転送し続け、データの複製を維持する仕組みです。RDS・Aurora・Cloud SQLのようなマネージドサービスがボタン1つでリードレプリカを作れるのに対し、Linuxサーバーを自前で運用する環境では、設定の意味を理解していないと障害時に即座に対処できません。
この記事では、Rocky Linux 9 / PostgreSQL 16 の2台構成(プライマリ1台・スタンバイ1台)を例に、ストリーミングレプリケーションの全手順を実際のコマンド出力とともに解説します。pg_basebackupでのベースバックアップ取得、standby.signalによる自動レプリケーション開始、pg_stat_replicationでの同期確認、そして障害時のスタンバイ昇格(フェイルオーバー)まで一気通貫でカバーします。
この記事のポイント
・pg_basebackup -R でstandby.signalとprimary_conninfoが自動生成される
・プライマリ側はwal_level・max_wal_senders・pg_hba.confの3か所を設定する
・pg_stat_replicationのstateが「streaming」になれば同期成立の合図
・スタンバイ昇格はpg_ctl promoteまたはSELECT pg_promote()で実行できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
ストリーミングレプリケーションの仕組みと構成イメージ
ストリーミングレプリケーションでは、プライマリサーバーがWAL(トランザクションログ)をWAL送信プロセス(walsender)経由でスタンバイへ継続的に転送します。スタンバイ側はWAL受信プロセス(walreceiver)で受け取り、データに適用することでプライマリと同じ状態を維持します。構成はシンプルで、必要なのはLinuxサーバー2台とPostgreSQLのみです。
・プライマリ:読み書き可能。WALを生成してスタンバイへ送信する。
・スタンバイ:読み取り専用(hot_standby=on の場合)。WALを受信してリカバリ状態で動作する。
PostgreSQL 12以降は、これまでの recovery.conf が廃止されています。代わりに、データディレクトリ直下に空のファイル「standby.signal」を置くことでスタンバイモードに入ります。接続先プライマリの情報は postgresql.auto.conf の primary_conninfo に書きます。pg_basebackup に -R オプションを付けると、この2ファイルを自動生成してくれるため、手動作業の手間を大幅に減らせます。
この記事で使う検証環境は以下のとおりです。
・OS: Rocky Linux 9.4
・PostgreSQL: 16.4(PGDGリポジトリ)
・プライマリ: 192.168.10.101(ホスト名: pg-primary)
・スタンバイ: 192.168.10.102(ホスト名: pg-standby)
・データディレクトリ: /var/lib/pgsql/16/data
構築前の確認事項(OS・ポート・PostgreSQLバージョン)
作業を始める前に、両サーバーで以下を確認します。PostgreSQLのバージョンが一致しているか確認する
プライマリとスタンバイのメジャーバージョンは同一でなければなりません(マイナーバージョンのズレは許容されますが、できれば揃えてください)。
# 両サーバーで実行して同じメジャーバージョンであることを確認する psql --version psql (PostgreSQL) 16.4
スタンバイからの接続を受け付けるため、プライマリの5432番ポートが開いている必要があります。Linux ポート確認の全コマンドで詳しく解説していますが、ss コマンドで素早く確認できます。
# プライマリ側で実行 ss -tlnp | grep 5432 LISTEN 0 128 0.0.0.0:5432 0.0.0.0:* users:(("postgres",pid=2341,fd=5)) LISTEN 0 128 [::]:5432 [::]:* users:(("postgres",pid=2341,fd=5))
ファイアウォールでスタンバイからの5432番アクセスを許可する
# プライマリ側でfirewalldを使っている場合 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.10.102/32" port protocol="tcp" port="5432" accept' firewall-cmd --reload # 設定確認 firewall-cmd --list-all | grep rich
プライマリサーバーを設定する
プライマリ側の変更は3か所です。postgresql.conf でWAL送信を有効化し、pg_hba.conf でスタンバイからの接続を許可し、レプリケーション専用ロールを作成します。1. postgresql.confでWAL送信設定を有効化する
postgresql.conf を開き、以下の3パラメータを設定します。# /var/lib/pgsql/16/data/postgresql.conf # WALの記録レベルをreplicaに上げる(デフォルトはreplica、念のため明示する) wal_level = replica # WAL送信プロセスの最大数(スタンバイ台数+余裕を持たせる) max_wal_senders = 5 # スタンバイが遅延した際に溜め置くWALの最大サイズ(PostgreSQL 13以降) wal_keep_size = 256
PostgreSQL 12以前を使っている場合は wal_keep_segments(セグメント数指定)が使われていましたが、13以降は wal_keep_size に統一されています。
2. pg_hba.confでレプリケーション接続を許可する
pg_hba.conf の末尾にレプリケーション専用の許可行を追加します。# /var/lib/pgsql/16/data/pg_hba.conf の末尾に追加 # TYPE DATABASE USER ADDRESS METHOD host replication replicator 192.168.10.102/32 scram-sha-256
pg_hba.conf の詳細な設定方法は別記事「pg_hba.confで接続認証を設計する方法」でも解説しています。
3. レプリケーションロールを作成してサービスを再起動する
スタンバイがプライマリへ接続する専用ロールを作成します。# プライマリ側でpsqlに接続して実行する sudo -u postgres psql -- REPLICATION属性を持つロールを作成する CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_password_here'; -- 作成確認 \du replicator List of roles Role name | Attributes ------------+------------------------------------------------------------- replicator | Replication postgres=# \q
# pg_hba.confはreloadで反映できるが、postgresql.confはrestartが必要なパラメータもある # wal_level・max_wal_senders の変更はrestartが必須 sudo systemctl restart postgresql-16 # 起動確認 sudo systemctl status postgresql-16 * postgresql-16.service - PostgreSQL 16 Database Server Loaded: loaded (/usr/lib/systemd/system/postgresql-16.service; enabled) Active: active (running) since Tue 2026-08-26 09:30:12 JST; 3s ago
pg_basebackupでスタンバイサーバーを構築する
スタンバイ側の構築はpg_basebackupコマンド1本で完結します。-R オプションを付けることで、standby.signal の作成と primary_conninfo の書き込みまで自動的に行われます。1. スタンバイ側のデータディレクトリを空にする
pg_basebackupはデータディレクトリが空でないと失敗します。initdb で作成済みのディレクトリがある場合は先に停止・クリアしてください。# スタンバイ側で実行する # PostgreSQLが動いていれば先に停止する sudo systemctl stop postgresql-16 # データディレクトリを空にする(既存データが消えるため慎重に) sudo rm -rf /var/lib/pgsql/16/data/* # ディレクトリが空になったことを確認 sudo ls -la /var/lib/pgsql/16/data/ total 0
2. pg_basebackupを実行してベースバックアップを取得する
スタンバイサーバー上でpg_basebackupを実行し、プライマリのデータを丸ごとコピーします。# スタンバイ側で postgres ユーザーとして実行する sudo -u postgres pg_basebackup \ -h 192.168.10.101 \ -U replicator \ -D /var/lib/pgsql/16/data \ -R \ -Xs \ -P Password: (replicatorのパスワードを入力) 32456/32456 kB (100%), 1/1 tablespace
・-h 192.168.10.101:プライマリのIPアドレス
・-U replicator:先ほど作成したレプリケーションロール
・-D /var/lib/pgsql/16/data:バックアップの出力先(スタンバイのデータディレクトリ)
・-R:standby.signal と primary_conninfo を自動生成する(最重要オプション)
・-Xs:バックアップ中にWALをストリーミングで取得する(WALが欠落しない)
・-P:進捗をパーセントで表示する
「100%」と表示されればベースバックアップの取得は完了です。
3. standby.signalとprimary_conninfoを確認する
-R オプションによって自動生成されたファイルを確認します。# standby.signal が作成されているか確認する ls -la /var/lib/pgsql/16/data/standby.signal -rw------- 1 postgres postgres 0 Aug 26 09:42 /var/lib/pgsql/16/data/standby.signal # primary_conninfo が postgresql.auto.conf に書き込まれているか確認する cat /var/lib/pgsql/16/data/postgresql.auto.conf # Do not edit this file manually! # It will be overwritten by the ALTER SYSTEM command. primary_conninfo = 'user=replicator host=192.168.10.101 port=5432 sslmode=prefer sslcompression=0'
パスワードを都度入力しないよう、.pgpass ファイルで認証情報を管理する場合は以下のように設定します。
# スタンバイの postgres ユーザーのホームディレクトリに .pgpass を作成する echo "192.168.10.101:5432:replication:replicator:strong_password_here" \ | sudo -u postgres tee /var/lib/pgsql/.pgpass # パーミッションを600にする(600以外だと無視される) sudo chmod 600 /var/lib/pgsql/.pgpass sudo chown postgres:postgres /var/lib/pgsql/.pgpass
4. スタンバイを起動してpg_stat_replicationで同期を確認する
スタンバイのPostgreSQLを起動します。# スタンバイ側で実行する sudo systemctl start postgresql-16 sudo systemctl status postgresql-16 * postgresql-16.service - PostgreSQL 16 Database Server Active: active (running) since Tue 2026-08-26 09:45:03 JST; 5s ago # スタンバイ自身がリカバリ状態にあるか確認する sudo -u postgres psql -c "SELECT pg_is_in_recovery();" pg_is_in_recovery ------------------- t (1 row)
次にプライマリ側でレプリケーションの状態を確認します。
# プライマリ側で実行する sudo -u postgres psql -c "SELECT pid, usename, application_name, client_addr, state, sync_state FROM pg_stat_replication;" pid | usename | application_name | client_addr | state | sync_state -------+------------+------------------+----------------+-----------+------------ 14237 | replicator | walreceiver | 192.168.10.102 | streaming | async (1 row)
pg_stat_replication に行が表示されない場合は、スタンバイからの接続自体がプライマリへ届いていない状態です。pg_hba.conf の設定ミスやファイアウォールの問題が多いため、後述のトラブルシュートを参照してください。
PostgreSQLのレプリケーション構築は、WAL設定・pg_hba.conf・pg_basebackupの連携を正しく理解していないと障害時に手が止まります。設定の意味から障害対応の判断軸まで、現役サーバー管理者が2日間のハンズオンで直接指導します。
スタンバイをプライマリへ昇格させる(フェイルオーバー)
プライマリが障害で応答しなくなった際は、スタンバイをプライマリへ昇格させます。この操作をプロモートまたはフェイルオーバーと呼びます。1. pg_ctl promoteまたはpg_promote()で昇格させる
昇格には2通りの方法があります。方法A: pg_ctl promote(コマンドライン)
# スタンバイサーバー上で実行する sudo -u postgres pg_ctl promote -D /var/lib/pgsql/16/data waiting for server to promote.... done server promoted
# スタンバイに接続してSQL実行でも昇格できる sudo -u postgres psql -c "SELECT pg_promote();" pg_promote ------------ t (1 row)
2. 昇格後の状態をpsqlで確認する
昇格後はpg_is_in_recovery()がfalseを返し、読み書き可能なプライマリとして動作します。# 昇格後のスタンバイ(新プライマリ)で実行する sudo -u postgres psql -c "SELECT pg_is_in_recovery();" pg_is_in_recovery ------------------- f (1 row) # 実際に書き込みができるか確認する sudo -u postgres psql -c "CREATE TABLE failover_test (id int);" CREATE TABLE sudo -u postgres psql -c "DROP TABLE failover_test;" DROP TABLE
昇格後に注意すること:
・旧プライマリが復旧した場合、そのままでは新プライマリに追随できません。旧プライマリを新プライマリのスタンバイとして再構成するには、pg_basebackupからやり直す必要があります。
・アプリケーションの接続先を新プライマリのIPアドレスへ切り替えてください。pgBouncer や HAProxy のような接続プールを使っている場合は、そちらの向き先変更も忘れずに行います。
「FATAL: could not connect to the primary server」が出た時の対処法
スタンバイ起動後に以下のようなエラーがジャーナルログに出る場合、原因は大抵5パターンのどれかです。# スタンバイ側でエラーを確認する sudo journalctl -u postgresql-16 --no-pager | tail -20 FATAL: could not connect to the primary server: connection to server at "192.168.10.101", port 5432 failed: FATAL: no pg_hba.conf entry for replication connection from host "192.168.10.102", user "replicator", SSL off
・pg_hba.confの設定漏れ:DATABASEに "replication"、ADDRESSにスタンバイのIPが正しく書かれているか確認してください。変更後は systemctl reload postgresql-16 で反映します。
・プライマリが再起動されていない:wal_level の変更はrestartが必要です。reloadでは反映されません。
・レプリケーションロールのパスワードが違う:primary_conninfo のpassword パラメータか .pgpass ファイルを確認します。
・ファイアウォールでポート5432がブロックされている:プライマリで firewall-cmd --list-all を確認してください。
・max_wal_sendersに達している:pg_stat_replication の行数が max_wal_senders と同数の場合、値を増やしてプライマリを再起動してください。
「FATAL: requested WAL segment has already been removed」が出る場合
# スタンバイのログに以下が出る場合はWALセグメントの欠落 FATAL: requested WAL segment 000000010000000000000005 has already been removed
本記事のまとめ
PostgreSQLのストリーミングレプリケーション構築で実施した手順を表にまとめます。| フェーズ | 実施箇所 | 内容 |
|---|---|---|
| プライマリ設定 | postgresql.conf | wal_level=replica、max_wal_senders=5、wal_keep_size=256 |
| プライマリ設定 | pg_hba.conf | host replication replicator スタンバイIP/32 scram-sha-256 |
| プライマリ設定 | psql | CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '…' |
| スタンバイ構築 | スタンバイ側コマンド | pg_basebackup -h プライマリIP -U replicator -D データdir -R -Xs -P |
| スタンバイ構築 | 自動生成ファイル確認 | standby.signal の存在・postgresql.auto.conf の primary_conninfo を確認 |
| 同期確認 | プライマリ側psql | pg_stat_replication の state が "streaming" になるを確認 |
| 同期確認 | スタンバイ側psql | SELECT pg_is_in_recovery() → t(true)を確認 |
| フェイルオーバー | スタンバイ側コマンド | pg_ctl promote -D データdir または SELECT pg_promote() |
| 昇格確認 | 新プライマリ側psql | SELECT pg_is_in_recovery() → f(false)を確認 |
PostgreSQLレプリケーションが構築できたら、次はLinuxサーバー全体の運用スキルを体系的に固めませんか?
レプリケーション・バックアップ・障害対応を含む現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:PostgreSQLのVACUUMとautovacuum運用設計|テーブル肥大化とXID周回を防ぐ設定の考え方
- この記事の属するカテゴリ:データーベース管理へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます