はじめに
本番環境でPostgreSQLを利用する場合、単一障害点を防ぐためにプライマリ-スタンバイ構成を構築することが推奨されます。この記事では、PostgreSQL 13.6を使用したストリーミングレプリケーションの設定手順と、フェイルオーバー時の操作を詳しく解説します。
環境の設定
- PostgreSQLバージョン: 13.6
- プライマリサーバIP: 192.168.1.10
- スタンバイサーバIP: 192.168.1.11
- データディレクトリ: /var/lib/pgsql/data
ストリーミングレプリケーションの設定手順
- プライマリサーバでレプリケーションユーザーを作成し、権限を付与する。(あらかじめフェイルオーバー時のアクセス設定をpg_hba.confで構成しておくことを推奨します)
- スタンバイサーバにPostgreSQLをインストールする。プライマリサーバと同じバージョンをインストールし、データディレクトリ(pgdata)とアーカイブディレクトリのファイルを削除します。この操作はスタンバイサーバで実行してください。
- スタンバイサーバで
pg_basebackupコマンドを使用して同期をセットアップする。 - スタンバイサーバを起動する。
具体的な操作コマンド
1. プライマリサーバでユーザーを作成し、権限を付与する
postgres=# CREATE ROLE sync_user LOGIN REPLICATION ENCRYPTED PASSWORD 'sync_pass_2024';
CREATE ROLE
2. pg_hba.confを設定し、スタンバイサーバからのアクセスを許可する
$ vim /var/lib/pgsql/data/pg_hba.conf
host replication all 192.168.1.10/32 md5
host replication all 192.168.1.11/32 md5
postgres=# SELECT pg_reload_conf(); -- 設定ファイルをリロード
3. スタンバイサーバでpg_basebackupを実行して同期をセットアップする
$ pg_basebackup -h 192.168.1.10 -U sync_user -p 5432 -F p -X s -v -P -R -D /var/lib/pgsql/data
Password:
pg_basebackup: base backup initiated
WARNING: skipping special file "./.s.PGSQL.5432"
pg_basebackup: write-ahead log start point: 0/30000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_12345"
pg_basebackup: base backup completed
4. スタンバイサーバを起動する
$ pg_ctl start -l /var/lib/pgsql/log/startup.log
waiting for server to start.... done
server started
データベースの同期状態を確認する
1. オペレーティングシステムのプロセスを確認する
プライマリサーバにはwalsenderプロセスが追加されます。
$ ps -ef | grep postgres | grep sender
postgres 7854 18709 0 11:19 ? 00:00:00 postgres: walsender sync_user 192.168.1.11(12836) streaming 0/1C0003E0
スタンバイサーバにはwalreceiverプロセスが存在します。
$ ps -ef | grep postgres
postgres 30471 1 0 11:19 ? 00:00:00 /usr/pgsql-13/bin/postgres
postgres 30472 30471 0 11:19 ? 00:00:00 postgres: startup recovering 00000001000000000000001C
postgres 30473 30471 0 11:19 ? 00:00:00 postgres: checkpointer
postgres 30474 30471 0 11:19 ? 00:00:00 postgres: background writer
postgres 30475 30471 0 11:19 ? 00:00:00 postgres: stats collector
postgres 30476 30471 0 11:19 ? 00:00:00 postgres: walreceiver
2. データベースのシステムビューを確認する
プライマリサーバではpg_is_in_recovery()がfを返し、スタンバイサーバではtを返します。
postgres=# SELECT pg_is_in_recovery();
pg_is_in_recovery
------------------
f
(1 row)
postgres=# SELECT pg_is_in_recovery();
pg_is_in_recovery
------------------
t
(1 row)
プライマリサーバでは、pg_stat_replicationビューをクエリしてスタンバイサーバの同期状態を確認できます。
postgres=# \x
Expanded display is on.
postgres=# SELECT * FROM pg_stat_replication;
-[ RECORD 1 ]----------------+------------------------------
pid | 7854
usesysid | 16436
usename | sync_user
application_name | walreceiver
client_addr | 192.168.1.11
client_port | 12836
backend_start | 2023-12-22 11:19:53.781303+08
state | streaming
sent_lsn | 0/1C0003E0
write_lsn | 0/1C0003E0
flush_lsn | 0/1C0003E0
replay_lsn | 0/1C0003E0
write_lag |
flush_lag |
replay_lag |
sync_priority | 0
sync_state | async
reply_time | 2023-12-22 11:24:24.29878+08
スタンバイサーバではpg_stat_wal_receiverビューで同期状態を確認できます。
postgres=# SELECT * FROM pg_stat_wal_receiver;
-[ RECORD 1 ]----------------+------------------------------
pid | 30476
status | streaming
receive_start_lsn | 0/1C000000
receive_start_tli | 1
written_lsn | 0/1C0003E0
flushed_lsn | 0/1C000000
received_tli | 1
last_msg_send_time | 2023-12-22 11:32:25.206129+08
last_msg_receipt_time | 2023-12-22 11:32:25.206617+08
latest_end_lsn | 0/1C0003E0
latest_end_time | 2023-12-22 11:19:53.783906+08
sender_host | 192.168.1.10
sender_port | 5432
conninfo | user=sync_user password=******** channel_binding=disable dbname=replication host=192.168.1.10 port=5432 fallback_application_name=walreceiver sslmode=disable sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres target_session_attrs=any
pg_stat_replicationの主要なフィールドの説明は以下の通りです。
sent_lsn: スタンバイに送信された最後のWAL位置(まだディスクに書き込まれていない)。write_lsn: スタンバイのオペレーティングシステムに書き込まれた最後のWAL位置(まだディスクにフラッシュされていない)。flush_lsn: スタンバイのディスクにフラッシュされた最後のWAL位置。replay_lsn: スタンバイでリプレイされた最後のトランザクションログ位置(ユーザーが見える状態)。
現在のWAL位置はpg_current_wal_lsn()で確認できます。主サーバとスタンバイサーバの遅延は、pg_current_wal_lsn() - replay_lsnで計算できます。
フェイルオーバー(主従切り替え)の手順
- プライマリサーバを停止する。
- スタンバイサーバで
pg_ctl promoteを実行してプライマリに昇格させる。 - アプリケーション設定を更新して新しいプライマリ(元スタンバイ)に接続する。(事前にVIPを設定している場合は、VIPを新しいプライマリに切り替える)
- 元プライマリサーバに
standby.signalファイルを作成し、postgresql.auto.confを設定して新しいプライマリサーバと同期する。 - 元プライマリサーバを起動し、新しいスタンバイサーバとして動作させる。注意: 非同期レプリケーションの場合、プライマリサーバがダウンするとデータ損失が発生する可能性があります。
フェイルオーバーの具体的な操作コマンド
1. プライマリサーバのシミュレーションダウン
$ pg_ctl stop -m immediate
waiting for server to shut down.... done
server stopped
この時点で、スタンバイサーバのpg_stat_wal_receiverには出力がありません。ログには同期エラーの情報が記録されます。
2. スタンバイサーバをプライマリに昇格させる
$ pg_ctl promote
waiting for server to promote.... done
server promoted
データベースログを確認すると、以下の情報が表示されます。
2023-12-22 11:45:44.835 CST [30472] LOG: received promote request
2023-12-22 11:45:44.835 CST [30472] LOG: redo done at 0/1C0003A8
2023-12-22 11:45:44.837 CST [30472] LOG: selected new timeline ID: 2
2023-12-22 11:45:44.883 CST [30472] LOG: archive recovery complete
2023-12-22 11:45:44.889 CST [30471] LOG: database system is ready to accept connections
元スタンバイサーバのstandby.signalファイルは自動的に削除されます。
3. 元プライマリサーバを新しいスタンバイサーバにする
データディレクトリに移動します。
$ cd /var/lib/pgsql/data
$ touch standby.signal
4. 新しいプライマリサーバの接続情報を設定する
$ vim postgresql.auto.conf
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
primary_conninfo = 'user=sync_user password=sync_pass_2024 channel_binding=disable host=192.168.1.11 port=5432 sslmode=disable sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres target_session_attrs=any'
5. 元プライマリサーバ(新しいスタンバイサーバ)を起動する
$ pg_ctl start
$ psql
psql (13.6)
Type "help" for help.
postgres=# \x
Expanded display is on.
postgres=# SELECT * FROM pg_stat_wal_receiver;
-[ RECORD 1 ]----------------+------------------------------
pid | 5776
status | streaming
receive_start_lsn | 0/1C000000
receive_start_tli | 2
written_lsn | 0/1C0026C8
flushed_lsn | 0/1C000000
received_tli | 2
last_msg_send_time | 2023-12-22 14:21:05.444004+08
last_msg_receipt_time | 2023-12-22 14:21:05.444451+08
latest_end_lsn | 0/1C0026C8
latest_end_time | 2023-12-22 14:20:35.378922+08
sender_host | 192.168.1.11
sender_port | 5432
conninfo | user=sync_user password=******** channel_binding=disable dbname=replication host=192.168.1.11 port=5432 fallback_application_name=walreceiver sslmode=disable sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres target_session_attrs=any