DBAtlas · データベース運用アトラス

PostgreSQL ストリーミングレプリケーション + 自動フェイルオーバー

症状

目標: ストリーミングレプリケーションで PostgreSQL のホットスタンバイを構築し、自動フェイルオーバーのために Patroni/repmgr を追加する。

1. プライマリで WAL と接続のパラメータを設定する

ストリーミングレプリケーションには、wal_level が少なくとも 'replica' である必要がある。max_wal_senders はレプリカ数 + バックアップ接続数をカバーし、wal_keep_size またはレプリケーションスロットで WAL の早期削除を防ぐ必要がある。変更には再起動が必要。

PostgreSQL

ALTER SYSTEM SET wal_level = 'replica';
ALTER SYSTEM SET max_wal_senders = 10;
ALTER SYSTEM SET max_replication_slots = 10;
ALTER SYSTEM SET hot_standby = on;
-- To apply the postgresql.conf change:
-- systemctl restart postgresql

2. レプリケーションロールと pg_hba のアクセスを定義する

スタンバイが接続に使う REPLICATION 属性付きのロールを作成する。スタンバイの IP から 'replication' データベースへのアクセスを許可する行を pg_hba.conf に追加し、pg_reload_conf() でリロードする。

PostgreSQL

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'secret';
-- Add to pg_hba.conf:
-- host replication replicator 10.0.0.20/32 scram-sha-256
SELECT pg_reload_conf();

3. プライマリに永続的なレプリケーションスロットを作成する

物理レプリケーションスロットは、スタンバイが遅延しても、プライマリが必要な WAL を削除するのを防ぐ。スロット管理は wal_keep_size より安全である。スロット名はスタンバイの構成で使う。

PostgreSQL

SELECT pg_create_physical_replication_slot('standby1_slot');
SELECT slot_name, active, restart_lsn FROM pg_replication_slots;

4. スタンバイサーバーで pg_basebackup によりベースバックアップを取る

スタンバイのデータディレクトリを空にした状態で、プライマリからフルコピーを取る。-R フラグは standby.signal ファイルと primary_conninfo を自動的に書き込み、-C でスロットも作成できる。スロット名は -S で渡す。

PostgreSQL

pg_basebackup -h 10.0.0.10 -U replicator -D /var/lib/pgsql/data \
  -R -X stream -S standby1_slot -P -v

5. primary_conninfo と hot_standby を確認し、スタンバイを起動する

-R により書き込まれた postgresql.auto.conf 内の primary_conninfo (host、user、slot) を確認する。standby.signal ファイルの有無がスタンバイモードを決める。hot_standby=on ならスタンバイは読み取り専用クエリを受け付ける。サービスを起動する。

PostgreSQL

-- Expected in postgresql.auto.conf:
-- primary_conninfo = 'host=10.0.0.10 user=replicator password=secret'
-- primary_slot_name = 'standby1_slot'
-- systemctl start postgresql
SELECT pg_is_in_recovery();  -- should return true on the standby

6. プライマリからレプリケーションラグを監視する

プライマリでは、pg_stat_replication が各スタンバイの送信済み/再生済み LSN とラグを示す。write/flush/replay のラグは小さく保たれるべきである。同期レプリカを使う場合、sync_state は 'sync' となる。

PostgreSQL

SELECT client_addr, state, sync_state,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes,
       write_lag, flush_lag, replay_lag
FROM pg_stat_replication;

7. 自動フェイルオーバーのために Patroni または repmgr を追加する

素のストリーミングレプリケーションでは手動の promote が必要。自動フェイルオーバーにはクラスタマネージャーが必要である: Patroni (etcd/Consul 上のリーダー選出 + 自動 promote) または repmgr (repmgrd による監視/フェイルオーバー)。アプリケーション側には HAProxy/pgBouncer で単一のエンドポイントを提供する。手動 promote が必要な場合: pg_ctl promote。promote の前に、旧プライマリが確実に停止しており、アプリケーションが書き込めないことを確認する (スプリットブレインのリスク)。旧プライマリを新プライマリのスタンバイとして再参加させるには pg_rewind が必要で、そのためには wal_log_hints = on またはデータチェックサムが有効である必要がある。

PostgreSQL

-- Manual promote (if there is no cluster manager):
pg_ctl promote -D /var/lib/pgsql/data
-- or via SQL:
SELECT pg_promote();
-- With Patroni: patronictl -c /etc/patroni.yml switchover mycluster
DBAtlas で開く →