はじめに
RDSやCloud SQLなどのマネージドサービスを使っていると、比較的容易に冗長化したDBクラスタを構築できると思います。
本記事では、その裏側で何が起きているのかを理解するために、
PostgreSQL + repmgr + pgpool-II + HAProxy の構成を
Docker上で再現しました。
本記事では、実装手順の細かな解説よりも、
Primary障害時に各コンポーネントがどのように動き、連携しているか
を説明していきます。
対象読者
- PostgreSQLのHA構成を初めて触る方
- repmgr/pgpool-II/HAProxyの組み合わせを実際に動かして理解したい方
- RDSやCloud SQLなどのマネージドサービスが、裏側でどう「自動フェイルオーバー」や「エンドポイント維持」を実現しているのか知りたい方
構成
使用技術
- PostgreSQL 15
- repmgr
- pgpool-II
- HAProxy
- Docker Compose
アーキテクチャ
この構成では HAProxy が単一障害点になるため、Keepalivedを用いたVIPや構成やクラウド環境であればALB/NLBなどのマネージドロードバランサを使うのが望ましいと思います。
Docker Compose 環境では VIP の扱いが難しいため、
本記事では **「接続口を固定する役割」**として HAProxy を利用しています。
各コンポーネントの役割
| コンポーネント | 役割 | 具体的な動作 |
|---|---|---|
| repmgr | フェイルオーバー判断・実行 | Primary障害を検知しStandbyを自動昇格 |
| pgpool-II | Primary自動検知 | 全ノードをヘルスチェックし書き込み先を自動切り替え |
| HAProxy | 接続口の一本化 | クライアントは常に同じエンドポイントに接続し、背後のpgpool切替を意識しない |
この構成の理由
PostgreSQL単体では、Primary障害時に以下の課題があります。
- Standbyが自動でPrimaryに昇格しない
- クライアントが接続先を手動で切り替える必要がある
これらの課題を上記で紹介したコンポーネントが解決してくれます。
Primary障害時に何が起きるか(時系列)
Primaryが停止した場合、内部では以下の流れが発生します。
1. repmgr(repmgrd)が障害を検知
repmgrdデーモンが定期的にPrimaryの生存確認を行い、接続不可を検知します。
内部的には、PostgreSQLプロトコルを用いた接続確認(PQping)やSQL実行を行い、DBプロセスが正常に応答するかを確認しています。
2. Standbyの1台が新Primaryへ昇格
repmgrは、あらかじめ設定された**優先度(priority)**に基づいて
昇格対象のStandbyを決定します。
Primary障害時、最も優先度の高いものが自動的に昇格します。
3. pgpool-IIが新Primaryを検知
pgpool-IIは sr_check(Streaming Replication Check)機能を使い、
登録されているすべてのPostgreSQLノードに対して定期的に以下のクエリを実行します。
SELECT pg_is_in_recovery();
この結果から、pgpool-IIはPrimaryを判定します。
falseを返すノード:Primary(書き込み可能)
trueを返すノード:Standby(読み取り専用)
4. 書き込み先が自動的に新Primaryへ切り替わる
3の判定でfalseを返したノード(Primary)を書き込み先として自動的に切り替えます。
まとめ
本記事では、PostgreSQLのHA構成をDocker上で再現しその挙動についての理解を深めていきました。
RDSやCloud SQLなどのマネージドサービスを使うと、フェイルオーバーは「いつの間にか終わっている魔法」のように見えますが、その裏側では本記事で見たような、「死活監視」「Primary判定」「接続先の切り替え」という処理が連携して行われています。
自前でこれらを構築・運用する手間などを考えると、
RDSやCloud SQLの料金が「可用性の対価」であることも改めて実感しました。