情報畑でつかまえてロゴ
本サイトは NTTテクノクロスが旬の IT をキーワードに
IT 部門が今知っておきたい最新テクノロジーに関する情報をお届けするサイトです

PostgreSQLでストリーミングレプリケーション(SR)環境はどう構築する?基本的な要点をおさえよう!

PostgreSQLのストリーミングレプリケーション(通称SR)の構築方法を初心者向けにご説明致します。

tx_postgres_sr_top.jpg

目次

1.はじめに
2.SRの仕組み
3.事前準備
4.DBクラスタの作成(プライマリサーバー)
5.パラメータ設定(プライマリサーバー)
6.pg_hba.confの設定(プライマリサーバー)
7.レプリケーションスロットの設定
8.初期データの導入
9.プライマリサーバーからのバックアップ取得
10.パラメータ設定(スタンバイサーバー)
11.pg_hba.confの設定(スタンバイサーバー)
12.レプリケーションの確認
13.よくあるエラー事象
14.まとめ

はじめに

こんにちは!NTTテクノクロスで PostgreSQL の技術支援とデータエンジニアをやっています、外山です。
今回は PostgreSQL の初学者に向け、ストリーミングレプリケーション(SR) の手順を分かりやすく解説していきます。

ストリーミングレプリケーションの仕組み

ストリーミングレプリケーションは、WAL(Write Ahead Logging)と呼ばれる「PostgreSQLへの更新要求があったに書き込まれるログ情報」を元に、リアルタイムで他の PostgreSQLサーバー上に全く同じデータベースを構築できる機能です。

本記事では、ユーザーが更新するデータベースサーバーの「プライマリーサーバー」1台、ログ情報を受け取るデータベースサーバーの「スタンバイサーバー」2台の、合計3台構成でストリーミングレプリケーション環境を作成したいと思います。

(構築イメージ)
構成図

事前準備

環境作成

1. サーバー準備

本記事では仮想マシン(VM)上でレプリケーションを構成します。(Oracle VM VirtualBOXなど)

<VMの環境設定>

・OS:RHEL ver9.0
・プロセッサ数: 2CPU
・メモリサイズ: 4096MB
・ストレージ: 30GB
・PostgreSQL: ver17.5

まず、プライマリーサーバー、スタンバイサーバー2台(合計3台)分の VM を、上記設定で作成します。

2. PostgreSQLのインストール、構築準備

※既にPostgreSQLのインストールができている方は飛ばしてください。
対象:プライマリーサーバー、スタンバイサーバー2台

RPMレポジトリのインストール


 $ sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-10-x86_64/pgdg-redhat-repo-latest.noarch.rpm 

postgresql(ver17)のインストール


 $ sudo dnf install -y postgresql17-server

PostgreSQL のバイナリコマンド(psql、initdb 等)を使用するために、PostgreSQL のパスを設定します。
※ OS の postgres ユーザで、「.bashrc」ファイルの最下部にパスを追記する。


 # su - postgres
 $ sudo vi ~/.bashrc

 (エディタ内:下記一文を追記します)
 PATH=$PATH:/usr/pgsql-17/bin

上記設定を反映させます。


 $ source ~/.bashrc

これにてPostgreSQLのバイナリコマンドを実行できるようになりました。 念のため、下記コマンドでバイナリコマンドを実行できるか確認してみてください。


 $ psql --version

DBクラスタの作成(プライマリサーバー)

DBクラスタとはデータベースの格納領域です。(標準SQLではカタログクラスタと呼ばれているものです)

対象:プライマリーサーバー
> 何かしら既にDBクラスタを作成している場合はこちらの手順も飛ばしてください。

DBクラスタとするディレクトリの作成

ディレクトリの配置場所は任意です。
今回は /home/postgres/primary 配下にDBクラスタを作成します。


 $ mkdir /home/postgres/primary

DBクラスタの作成(初期化)

initdbコマンドで先ほど作成したディレクトリ内にDBクラスタを作成します。


 $ initdb --data-checksums --no-locale -D /home/postgres/primary --encoding=UTF8
 The files belonging to this database system will be owned by user "postgres".  This user must also own the server process.
 The database cluster will be initialized with locale "C".  The default text search configuration will be set to "english".
 Data page checksums are enabled.
 fixing permissions on existing directory /home/postgres/primary ... ok  creating subdirectories ... ok  selecting dynamic shared memory implementation ... posix  selecting default "max_connections" ... 100  selecting default "shared_buffers" ... 128MB  selecting default time zone ... Asia/Tokyo  creating configuration files ... ok  running bootstrap script ... ok  performing post-bootstrap initialization ... ok  syncing data to disk ... ok
 initdb: warning: enabling "trust" authentication for local connections  initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.
 Success. You can now start the database server using:

PostgreSQL を起動します。


 pg_ctl -D /home/postgres/primary -l logfile start

パラメータ設定(プライマリサーバー)

ここでは、プライマリサーバー側のレプリケーションに関するパラメータについてざっくり説明します。
(スタンバイサーバーに関しては後述)

ファイル /home/postgres/primary/postgresql.conf の最後尾に下記パラメータ設定を付け加えます。

パラメータ名設定値内容
listen_addresses'*'クライアントからの接続を監視するTCP/IPアドレスを指定(注意: '*'でなく、IPアドレスを指定する場合は自身が持つIPアドレスを書くことになる)。
wal_levelreplicaWALの情報量を指定。レプリケーション構成にする場合はreplica 以上に設定する。
max_wal_senders10同時に稼動するWAL送信プロセスの最大数。
max_replication_slots10レプリケーションスロット(後述)の最大数。
synchronous_standby_names(※)'FIRST 1 (standby1)'同期スタンバイサーバのリスト。指定したスタンバイサーバーがデータを受信したことを確認するまでプライマリサーバーはコミットを待機する。左はスタンバイサーバーのうち1台が同期、2台目が非同期の場合。
archive_modealwaysarchive_modeが有効(on / always)な場合、完了したWALセグメントはアーカイブ格納領域に送信される。
archive_command'/bin/cp %p /mnt/archive/pg_archive/%f'archive_modeが有効な時、左記のコマンドにより /mnt/archive/pg_archive 下にアーカイブファイルを保存させる

※後述の「初期データの導入」が終了するまでは sychronous_standby_names はコメントアウトしてください。
スタンバイサーバーの準備ができていない状態で本パラメータを設定してしまうと、プライマリサーバーがコミット待機を続けてしまい、上手くテーブルを作成できなくなります。

(記述例)
postgresql.conf

アーカイブWALを格納するディレクトリの作成

対象: プライマリサーバー、スタンバイサーバー2台
サーバーパラメータ archive_command にて mnt/archive/pg_archive 配下にアーカイブが格納されるよう設定しましたが、ディレクトリはご自身で作成しておく必要があります。
今回はスタンバイサーバーも同じディレクトリ構成にするため、3台すべてに mkdir コマンドを実行します。


 $ sudo mkdir -p /mnt/archive/pg_archive
 # ディレクトリの所有者をPostgreSQLの実行ユーザに変更  $ sudo chown postgres:postgres /mnt/archive/pg_archive

pg_hba.confの設定(プライマリサーバー)

こちらもまずはプライマリサーバーの設定方法だけ記載します。
ファイル /home/postgres/primary/pg_hba.conf の該当箇所を下記に変更します。


 # IPv4 local connections:
 local   all    all                     trust
 host    all    all    <プライマリーサーバのIPアドレス>    trust  # Primary機
 # replication privilege
 local   replication   all                  trust
 host    replication   all  127.0.0.1/32    trust
 host    replication   all  <プライマリーサーバ1のIPアドレス>   trust   # Standby1機
 host    replication   all  <プライマリーサーバ2のIPアドレス>   trust   # Standby2機

(記述例)
postgresql.conf

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

レプリケーションスロットを使用することで、以下を実現できます。

・全てのスタンバイサーバーが WALセグメントを受け取るまで、プライマリサーバーがWALセグメントを削除しないことを保証する
・スタンバイサーバーが接続していない場合、リカバリの競合が発生する可能性がある行をプライマリサーバーが削除しないことを保証する

psqlに接続し、下記コマンドを実行することでレプリケーションスロットを作成できます。
対象:プライマリーサーバー

・レプリケーションスロットはスタンバイサーバーの数だけ用意する(下記は3台構成でスタンバイが2台の場合)。


 ※プライマリ側のPostgreSQLの起動
 $ pg_ctl start -D /home/postgres/primary
 (省略)
 $ psql 
 psql (17.4)
 Type "help" for help.
 postgres=# SELECT * FROM pg_create_physical_replication_slot('repl_slot1');   slot_name | lsn  ------------+-----   repl_slot1 |
 postgres=# SELECT * FROM pg_create_physical_replication_slot('repl_slot2');   slot_name | lsn  ------------+-----   repl_slot2 |

作成したレプリケーションスロットを確認します。


 postgres=# select * from pg_replication_slots;
   slot_name  | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn | wal_status | safe_wal_size | two_phase |        inactive_since         | conflicting | invalidation_reason | failover | synced 
  ------------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------+------------+---------------+-----------+-------------------------------+-------------+---------------------+----------+--------
  repl_slot_1 |        | physical  |        |          | f         | f      |            |      |              |             |                     |    |               | f         | 2025-04-16 08:19:05.232003+00 |             |                     | f        | f
  repl_slot_2 |        | physical  |        |          | f         | f      |            |      |              |             |                     |    |               | f         | 2025-04-16 08:19:37.059018+00 |             |                     | f        | f
 (2 rows) 

初期データの導入

プライマリーサーバーにレプリケーションさせるデータを導入します。今回はPostgreSQLのベンチマークに使用されるpgbenchを使用し、疑似的なデータベースを作成していきます。

・pgbenchを使用して、Primary機にデータを投入する。
・-s オプションにはスケールファクタ(データサイズ:スケール1は15MB)を指定する。
・初期データ投入の段階でレプリケーション構成は組まず、単体構成で行う。


 $  pgbench -i -s 100
 dropping old tables...
 NOTICE:  table "pgbench_accounts" does not exist, skipping
 NOTICE:  table "pgbench_branches" does not exist, skipping
 NOTICE:  table "pgbench_history" does not exist, skipping
 NOTICE:  table "pgbench_tellers" does not exist, skipping
 creating tables...
 generating data (client-side)...
 vacuuming...                                                                                  
 creating primary keys...
 done in 79.17 s (drop tables 0.03 s, create tables 0.09 s, client-side generate 65.35 s, vacuum 0.77 s, primary keys 12.94 s).

スタンバイデータベースクラスタの作成(プライマリサーバーからのバックアップ取得)

スタンバイデータベースクラスタは、稼動中のデータベースクラスタをコピーすることで作成します。
コピーには pg_basebackup というバックアップ用のコマンドを用います。
pg_basebackup のコマンドは、スタンバイサーバー上から実行します。

-R オプションを指定すると postgresql.auto.conf が作成されます。
このファイルにはプライマリサーバーへの接続情報など、レプリケーションを行うための設定が自動で記載されます。
※ただし、変更する場合は手動で編集できず、ALTER SYSTEM コマンドを使用することに注意


 # スタンバイサーバー1から実行
 $ cd /home/postgres
 $ pg_basebackup -R -h <プライマリサーバーのIPアドレス> -p 5432 -U postgres -D standby1
 # スタンバイサーバー2から実行  $ cd /home/postgres  $ pg_basebackup -R -h <プライマリサーバーのIPアドレス> -p 5432 -U postgres -D standby2

取得できない場合はプライマリサーバーのファイアウォール設定などを確認してみてください。

プライマリサーバー側のファイアウォールで、ポート5432(PostgreSQLが使用するポート)を解放する。


 # 永続的にポートを開放する
 sudo firewall-cmd --zone=public --add-port=5432/tcp --permanent
 # 設定を反映させるためにfirewalldをリロードします。
 sudo firewall-cmd --reload

パラメータ設定(スタンバイサーバー)

スタンバイサーバーの postgresql.conf ファイルの中身に下記を付け加えます。cluster_name と primary_slot_name は適宜スタンバイサーバーに応じて選択してください。

「スタンバイサーバー1用の設定」(同期レプリケーション)

パラメータ名設定値内容
listen_addresses'*'
hot_standbyon
cluster_name'standby1'プライマリサーバーの synchronous_standby_names に対応するクラスター名を記入。
primary_slot_name'repl_slot1'「レプリケーションスロットの設定」で作成した名前を書く。
archive_modealways
archive_command'/bin/cp %p /mnt/archive/pg_archive/%f'


「スタンバイサーバー2用の設定」(同期レプリケーション)

パラメータ名設定値
listen_addresses'*'
hot_standbyon
cluster_name'standby2'
primary_slot_name'repl_slot2'
archive_modealways
archive_command'/bin/cp %p /mnt/archive/pg_archive/%f'

※ プライマリサーバーのバックアップで作成したため、postgresql.conf はプライマリサーバー上の設定になっていると思います。
 syncronous_standby_names など、不要な項目は適宜削除またはコメントアウトしてください。

(記述例)
■スタンバイサーバー1
postgresql.conf

■スタンバイサーバー2
postgresql.conf

pg_hba.confの設定(スダンバイサーバー)

こちらもスタンバイサーバー2台の設定をしていきます。 プライマリーサーバーの設定が残っていますので、2台とも下記設定に変更してください。


 ### IPv4 local connections:
 local   all    all                     trust
 host    all    all      127.0.0.1/32   trust
 ### replication privilege
 local   replication   all                  trust
 host    replication   all  127.0.0.1/32    trust   

※ プライマリーサーバーで設定していたレプリケーション情報は削除します。
(記述例)
postgresql.conf

レプリケーションの確認

プライマリーサーバー側の postgresql.conf の synchronous_standby_names のコメントアウトを外し、 プライマリーサーバー側の PostgreSQL を再起動します。


 $ pg_ctl restart -D /home/postgres/primary

その後、スタンバイ2台を起動します。


 $ pg_ctl start -D /home/postgres/standby1

 $ pg_ctl start -D /home/postgres/standby2

下記コマンドで実際にレプリケーション構成が取れているか確認します。
コマンドはプライマリーサーバー上で実行します。

・application_name:設定したアプリケーションネームになっているか
・client_addr:IPアドレスが正しいか
・sync_state:sync(同期)になっているか、又はasync(非同期)になっているか


 $psql
 postgres=# select * from pg_stat_replication;
 pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_sta  rt | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | r  eplay_lag | sync_priority | sync_state | reply_time  ------+----------+----------+------------------+----------------+-----------------+-------------+--------------------  -----------+--------------+-----------+------------+------------+------------+------------+-----------+-----------+--  ----------+---------------+------------+-------------------------------  1439 | 10 | postgres | standby1 | 192.168.56.104 | | 34754 | 2025-10-28 10:13:04  .606637+09 | | streaming | 0/550000D8 | 0/550000D8 | 0/550000D8 | 0/550000D8 | | |   | 1 | sync | 2025-10-28 10:16:26.204806+09  1447 | 10 | postgres | standby2 | 192.168.56.106 | | 38160 | 2025-10-28 10:15:35  .503777+09 | | streaming | 0/550000D8 | 0/550000D8 | 0/550000D8 | 0/550000D8 | | |   | 0 | async | 2025-10-28 10:16:28.285475+09  (2 rows)

また、プライマリ、スタンバイ両方のログを確認して、無事レプリケーションができているか確認してください。
・ログの所在:/home/postgres/primary/log/


 <プライマリー側>
 LOG:  standby "standby1" is now a synchronous standby with priority 1
 <スタンバイ側>  LOG: started streaming WAL from primary at 0/53000000 on timeline 1

データ挿入による確認

プライマリーサーバー上の現在のテーブルを確認、新規テーブルを挿入します。


 $ psql
 psql (17.6)
 Type "help" for help.
 postgres=# \d   List of relations   Schema | Name | Type | Owner  --------+------------------+-------+----------   public | pgbench_accounts | table | postgres   public | pgbench_branches | table | postgres   public | pgbench_history | table | postgres   public | pgbench_tellers | table | postgres  (4 rows)

続いて、新規にテーブルを作成します。


 postgres=# CREATE TABLE my_table (
 id SERIAL PRIMARY KEY,                      
 name VARCHAR(50) NOT NULL,                      
 age INTEGER,                  
 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 );
 CREATE TABLE
 postgres=# \d   List of relations   Schema | Name | Type | Owner  --------+------------------+----------+----------   public | my_table | table | postgres   public | my_table_id_seq | sequence | postgres   public | pgbench_accounts | table | postgres   public | pgbench_branches | table | postgres   public | pgbench_history | table | postgres   public | pgbench_tellers | table | postgres  (6 rows)

スタンバイサーバー側からも、新規作成したテーブルが表示されていればレプリケーションは成功していることが確認できます。

よくあるエラー事象

■ WALアーカイブが格納されるディレクトリへのアクセス権限がない
 postgresql.conf の archive_command で、アーカイブWALを保有するディレクトリの所有者が rootユーザなどになっており、アーカイブWALが保存できず上手くレプリケーションができないケースがありえます。
 ⇒chownコマンドで postgresユーザに所有者を変更しましょう。

■ レプリケーションに必要なWALファイルがなくなっている
 pg_basebackup の実行から時間が経ってしまうと、レプリケーションに必要な WALがプライマリーサーバー上から削除されてしまい上手くレプリケーションできないことが考えられます。
 ⇒その場合は、再度 pg_basebackup を使用してバックアップを取りなおす必要があります。

■ プライマリーサーバー側のFW設定でスタンバイサーバーからの接続がはじかれている
 postgresql.conf に記載した primary_conninfo の設定に従ってスタンバイサーバーからプライマリーサーバーに接続しようとしたところ、ファイアウォールの設定やSELINUXの設定で接続ができないケースが考えられます。
 ⇒ファイアウォールの設定を弱める場合はセキュリティに問題が無いことを確認して設定してください。

まとめ

無事にストリーミングレプリケーション環境を構築できましたでしょうか? 本記事が PostgreSQL を初めて扱う方の参考になれば幸いです。

PostgreSQLのことならNTTテクノクロスにおまかせください!

NTTテクノクロス株式会社ではPostgreSQLに関する各種のお問い合わせや、移行に関する対応を受け付けています。
オンプレだけではなく、Azure、AWSなどのクラウド上でのシステムの導入、開発、維持管理のご相談もお待ちしております。

PostgreSQL の定額制チケットサービスはこちら


PostgreSQLへの移行サービスはこちら

著者プロフィール
外山 大夢
外山 大夢

NTTテクノクロス株式会社
IOWNデジタルツインプラットフォーム事業部
第三ビジネスユニット