代表的な面接トピック

バックエンド面接:PostgreSQLの論理レプリケーションフェイルオーバーをどのように設計しますか?

バックエンド難しい
Offer.cc 編集チーム公開日 更新日

質問

本番環境のPostgreSQLデータベースから変更を読み取るCDCコンシューマーを運用しています。計画的なスイッチオーバーや予期しない障害の発生時、重複、データの欠落(ギャップ)、WALの肥大化、あるいは根拠のない「データ損失ゼロ」の主張を隠すことなく、新しいプライマリが同じ論理レプリケーションスロットの処理を継続できるようにするにはどうすればよいですか?

プロンプトと適用範囲

本番環境のPostgreSQLデータベースから変更を読み取るCDCコンシューマーを運用しています。計画的なスイッチオーバーや予期しない障害の発生時、重複、データの欠落(ギャップ)、WALの肥大化、あるいは根拠のない「データ損失ゼロ」の主張を隠すことなく、新しいプライマリが同じ論理レプリケーションスロットの処理を継続できるようにするにはどうすればよいですか?PostgreSQL 18のフェイルオーバースロット、同期チェック、コンシューマーの再接続、監視、ロールバックについて説明してください。

PostgreSQLのドキュメントには、論理レプリケーションスロットを物理スタンバイに同期できると記載されていますが、スロットの同期は非同期です。スタンバイを昇格させる前に、必要なスロットが存在し、failover_ready として報告されている必要があります。このバックエンドの信頼性に関する質問では、データベースの機能、コンシューマーのセマンティクス、フェイルオーバーのオーケストレーションを検証可能なプロセスへと結び付けられるかがテストされます。

面接官が評価するポイント

  • 物理WALレプリケーション、論理レプリケーションスロット、コンシューマーのアック(確認応答)の区別。
  • failover スロットオプションおよび synchronized_standby_slots の境界の説明。
  • 計画的なスイッチオーバーと突然の障害における、異なる損失・重複ウィンドウの処理。
  • 稼働中のスタンバイが存在することが、すべての論理スロットの準備完了を証明するものではないことの理解。
  • WAL保持、スロットの遅延(ラグ)、再接続、コンシューマーの遅延に対するアラート設計。
  • 接続検出、フェンシング、ダウンストリームの冪等性を明示的なコンポーネントに割り当てること。

尋ねるべき確認事項

  1. コンシューマーは別のPostgreSQLサブスクライバーですか、それともDebeziumなどの非PostgreSQL CDCクライアントですか?準備状況のチェック方法が異なります。
  2. 目標は計画的なほぼデータ損失ゼロの切り替えですか、それともクラッシュ後の制限された復旧ポイントですか?
  3. ダウンストリーム側でLSN、トランザクションID、イベントID、またはビジネスキーによる重複排除が可能ですか?
  4. プライマリとスタンバイで同じPostgreSQLメジャーバージョンおよび出力プラグインを使用していますか?
  5. スタンバイの昇格、ディスカバリの変更、旧プライマリのフェンシング、スプリットブレインの防止を行うコーディネーターは何ですか?

30秒の回答

まず目標復旧ポイント(RPO)と重複の許容度を定義し、スロットの同期、昇格、再接続、ダウンストリームの冪等性をステートマシンとしてモデル化します。昇格後も存続させる必要がある各論理スロットでフェイルオーバーを有効にし、スタンバイ上で各スロットの存在、同期状態、failover_ready の値を確認します。切り替え時は、ディスカバリを変更する前に旧プライマリをフェンシングします。コンシューマーは記録されたLSNから再開し、再送されたトランザクションはLSNやビジネスキーによる冪等性によって無害化します。スロットの遅延、保持されたWAL、コンシューマーの遅延、再接続の結果を監視し、非同期のスロット同期を損失ゼロの保証として扱いません。

ステップバイステップの詳細解説

1. データセマンティクスの定義

設計にRPO、RTO、重複処理を組み込みます。計画的なスイッチオーバーでは必要なスロットの同期を待機できますが、突然の障害では昇格したスタンバイに到達したWALからしか復旧できません。コンシューマーは最後に確認したLSNまたは同等の位置を永続化する必要があり、副作用を伴う処理には冪等性キーを使用する必要があります。

2. フェイルオーバー対応の論理スロットの設定

PostgreSQL 18は、スタンバイに同期可能な論理スロットをサポートしています。スロットまたはサブスクリプションの作成時にフェイルオーバーオプションを有効にし、コンシューマー群が必要とするすべてのスロットのインベントリを維持します。テーブル同期スロットやセカンダリコンシューマーを忘れないようにしてください。

sql
-- Illustrative only: allow a logical slot to synchronize to a standby
SELECT *
FROM pg_create_logical_replication_slot('cdc_orders', 'pgoutput', false, true);

正確なシグネチャと権限は、デプロイされたPostgreSQLのバージョンおよびプラグインと一致している必要があります。この例は設定および互換性のチェックを代替するものではありません。

3. 物理レプリケーションを通じたスロット状態の伝達

WALを受信するように物理スタンバイを設定し、ドキュメントに記載されたフェイルオーバーワークフローで必要な場合は synchronized_standby_slots を使用します。昇格の前に、スタンバイ上で pg_replication_slots を確認し、必要なすべてのスロットが存在し、同期されており、failover_ready であることを確認します。スロットのコピーは非同期であるため、健全なストリーミング接続だけでは不十分です。

4. 計画的なスイッチオーバー

CDCコンシューマーを一時停止またはドレインし、最後に確認された位置を記録します。旧プライマリへの書き込みを停止し、物理レプリケーションとスロットの同期を待ちます。両方のノードでスロットインベントリを照合し、必要なすべてのスロットの準備が整った後にのみ昇格を実行し、その後接続ディスカバリを変更して同じ論理スロットからコンシューマーを再開します。境界部分が再送された場合、ダウンストリームのLSNチェックまたは冪等性によって重複の影響を排除します。

5. 突然の障害とスプリットブレインの防止

クラッシュ時にはスロットの同期を待つことができません。旧プライマリが復帰して書き込みを行う前にフェンシングし、昇格されたノードによって証明される復旧ポイントを計算します。コーディネーターは、1つのノードのみが書き込み可能であることを保証する必要があります。DNS、VIP、またはサービスディスカバリの変更後、コンシューマーはサーバーIDとスロットの存在を検証する必要があります。同期されていないスロットは不完全なハンドオフとして報告される必要があり、手動リカバリまたはサブスクリプションの再構築を明示的な選択肢として用意します。

6. WAL保持とコンシューマーの進行状況の監視

各スロットの restart_lsnconfirmed_flush_lsn、スロットの遅延、保持されたWAL、再接続回数、エンドツーエンドの遅延を追跡します。放置されたスロットはWALの再利用を妨げ、ディスクを逼迫させる可能性があります。「スロットが存在する」アラートと「コンシューマーが目標LSNまで処理した」アラートを分離し、リカバリのためのタイムアウト、スロットル、人手による介入のしきい値を設定します。

7. ロールバック、再構築、および受け入れ

準備チェックが失敗した場合は自動昇格を行わず、旧プライマリを維持するか、宣言されたデグラデーションモードに移行します。計画的なスイッチオーバー、突然の電源喪失、コンシューマーの切断、スロット同期の遅延、旧プライマリの再起動を演習します。最後のコミット、新しいプライマリでの最初のイベント、重複カウント、ギャップ数、RTO、ピーク時のディスク使用量を記録します。すべてのギャップをLSNまで追跡します。

高品質な回答例

ワークフローを6つの状態としてモデル化します:スロット準備完了、旧プライマリのフェンシング、スタンバイ昇格、ディスカバリ切り替え、コンシューマー再開、ダウンストリーム位置確認。必要な論理スロットでフェイルオーバーを有効にし、すべてのスロットが存在して failover_ready になるまでスタンバイ上で synchronized_standby_slotspg_replication_slots を検査します。同期は非同期であるため、スタンバイが稼働していることだけでは安全な昇格の十分な証拠にはなりません。

計画的な切り替えの場合、コンシューマーを一時停止し、旧プライマリへの書き込みを凍結し、物理レプリケーションとスロットの同期を待ってから昇格します。クラッシュの場合、旧プライマリをフェンシングし、損失ゼロを主張するのではなく復旧可能なRPOを明示します。コンシューマーは再接続して保存されたLSNから再開し、ダウンストリームの冪等性がリプレイを吸収します。最後に、スロット遅延、WAL保持、コンシューマー遅延、再接続、ギャップを監視し、電源喪失や同期遅延の訓練によってRPOとRTOを検証します。

よくある間違い

  • スタンバイがオンラインであることだけを理由に昇格させる → スロットの同期がまだ完了していない可能性があります → 各スロットの存在、同期状態、failover_ready を確認してください。
  • 論理スロットをコンシューマーがデータを処理したことの証明として扱う → スロットの状態とダウンストリームの確認応答は異なります → LSNとコンシューマーの位置を個別に追跡してください。
  • クラッシュに対して損失ゼロを約束する → 同期されていないWALは利用できない可能性があります → 計画時と計画外のRPOを個別に明示してください。
  • 旧プライマリをフェンシングせずにDNSを変更する → スプリットブレインによる書き込みの可能性が残ります → 最初にフェンシングを行い、その後に昇格とディスカバリの切り替えを行ってください。
  • 停止したスロットを放置する → 保持されたWALがディスクを枯渇させる可能性があります → 遅延、ディスク使用量、最大保持期間についてアラートを設定してください。
  • データベースの昇格のみをテストする → コンシューマー、プラグイン、ダウンストリームの処理で障害が発生する可能性があります → エンドツーエンドのリプレイ訓練を実施してください。

フォローアップの質問と回答

failover_ready はイベントが失われないことを証明しますか?

いいえ。これは、関連する論理スロットがターゲットスタンバイに同期されており、昇格後も継続できることを示しているだけです。損失の有無は、障害発生時の物理レプリケーション、コンシューマーの確認応答位置、およびダウンストリームの処理セマンティクスに依然として依存します。

なぜ計画的な切り替え中にコンシューマーを一時停止するのですか?

一時停止することで最後に確認された位置が固定され、コンシューマーが古いプライマリと新しいプライマリから同時に読み取ることを防止できます。より高度なコーディネーターも可能ですが、スプリットブレイン、順序の乱れ、曖昧な確認応答を防ぐことが証明されている必要があります。

非PostgreSQL CDCクライアントはどのように準備状況を検証すべきですか?

PostgreSQLのサブスクリプションクエリを直接再利用することはできません。独自のスロットインベントリとヘルスチェックを維持し、スタンバイ上の同期されたスロットを検証した上で、クライアントプロトコルを使用して新しい接続と位置の継続性を検証する必要があります。

スロットが同期されていないにもかかわらず、ビジネス上リカバリが必要な場合はどうしますか?

実際のRPOを明示し、安全側の復旧ポイントを選択します。必要に応じてスロットを再構築するか、新しいスナップショットを取得するか、バックアップから補正します。検証されていないレプリケーション状態を損失のないリカバリとして提示してはなりません。

旧プライマリの復帰をどのように阻止しますか?

コーディネーターまたはクラウドのフェンシング、ネットワーク分離、書き込み認証情報のローテーションを使用します。DNSの変更だけでは、旧プライマリが書き込みを受け入れるのを防ぐことはできません。

リプレイによって重複の副作用が発生しなかったことをどのように証明しますか?

トランザクションLSN、イベントID、または冪等性キーによって重複を排除し、訓練中にリプレイ数、最終的なビジネストータル、順序制約を記録します。切り替え前後の監査可能な位置を比較します。

公開情報ソース

関連する質問