Automated failover

プライマリで予期しないエラーが.spec.failoverDelay デフォルトでは0 秒より長く発生した場合、クラスターは フェールオーバーモード になります。これは、たとえば次の場合に発生する可能性があります。

  • プライマリポッドにディスク障害が発生した

  • プライマリポッドが削除された

  • プライマリのpostgres コンテナに何らかの持続的な障害がある

フェールオーバーシナリオでは、プライマリが正常に動作していると想定できません。

上記のような場合の後、プライマリポッドの準備状況プローブは失敗し始めます。これは、コントローラの調整ループで取得されます。コントローラは、2つの手順でフェールオーバープロセスを開始します。

  1. 最初に、TargetPrimary をpending としてマークします。この状態の変更は、プライマリポッドを強制的にシャットダウンし、レプリカのWALレシーバーが停止します。クラスターは、フェールオーバーフェーズ「フェールオーバー」でマークされます。

  2. すべてのWALレシーバーが停止すると、リーダー選挙が行われ、新しい予備選挙が名前付けられます。選択されたインスタンスはプライマリへの昇格を開始し、これが完了すると、クラスターは通常のオペレーションを再開します。一方、以前のプライマリポッドは再起動し、プライマリでなくなったことを検出し、レプリカノードになります。

注釈

2フェーズプロシージャは、WALレシーバーが正常に停止でき、障害が発生したプライマリが再起動時にWALのストリーミングを再度開始しないことを保証します。これらの安全対策は、新しいプライマリとレプリカ間のタイムラインの不一致を防ぎます。

障害が発生したプライマリがシャットダウンされている間

  1. 最初に.spec.switchoverDelay 秒をタイムアウトとしてPostgreSQLの_fast shutdown_を試行します。この正常なシャットダウンは、保留中のWALをアーカイブしようとします。

  2. 高速シャットダウンが失敗するか、そのタイムアウトを超過すると、PostgreSQLの_即時シャットダウン_が開始されます。

注釈

「Fast」モードは、PostgreSQLクライアントが切断されるのを待機せず、進行中のオンラインバックアップを終了します。アクティブなトランザクションはすべてロールバックされ、クライアントは強制的に切断され、サーバーはシャットダウンされます。 「Immediate」モードは、クリーンシャットダウンせずに、すべてのPostgreSQLサーバープロセスをすぐに中止します。

安全な予備選挙

任意の時点で、最大1つのインスタンスがプライマリに昇格するように保証には、CloudNativePGは、 Cluster にちなんで名前付けられ、その名前空間に存在するKubernetes Lease オブジェクトを使用して上記の選択をサポートします。インスタンスは、プライマリに昇格する前に、このリースを取得および保持する必要があります。クリーンなシャットダウンでは、元のプライマリはリースを解放するため、資格のあるレプリカは、リースの有効期限が切れるのを待たずに引き継ぐことができます。

プライマリリースが保護するもの

以前のプライマリからストリーミングするのではなく、アーカイブからWALファイルを読み取ることにより、レプリカが追いつくことを検討します。 PostgreSQLは、アーカイブが次の予想セグメントで「ファイルが見つかりません」を返すとすぐに再生を停止し、WALストリームの終わりとして扱います。以前のプライマリがまだWALを持っているときにレプリカが昇格した場合、アーカイブが終了していないため、その信号はストリームの真の終了前に到着します。レプリカは、以前のプライマリが確認され、これらの書き込みより前のLSNで新しいタイムラインをフォークします。失われています。

リースは、以前のプライマリがリリースするまでプロモーションを保持します。クリーンシャットダウンでは、PostgreSQLが残りのWALをフラッシュしてアーカイブした後にリリースが発生するため、引き継ぐレプリカは最終的な端でアーカイブを参照します。以前のプライマリがリースを解放できない場合 クラッシュ、ノード障害、またはインスタンスマネージャー自分自身に到達不能そのパスでは、アーカイブが追いついていない可能性があり、以前のプライマリがアーカイブを完了していなかった書き込みは失われます。

一次分離チェックとの関係

リースは、Kubernetes APIサーバーへの接続を失ったものの、まだ実行されているプライマリをフェンスしません。これが 一次分離チェックとの関係 チェックのジョブです。 2つのメカニズムは補完的であり、両方ともデフォルトで有効になっています。

  • リースは、_premature_プロモーションを防止します。元のプライマリがまだリースを保持している間、レプリカは昇格できません。

  • 分離チェックは、 _isolate_プライマリが書き込みの受け入れを継続しないようにします。

両方を有効にしたままにします。分離チェックを無効にすると、リースだけがプライマリの安全性を担当し、元のプライマリがAPIサーバーに到達できないが、それ以外は正常な場合、リースだけではスプリットブレインを防ぐことはできません。

プライマリリースの検査

リースはクラスターの名前を共有するため、直接検査できます。 cluster-example というクラスターの場合

kubectl get lease cluster-example

HOLDER 列は、現在のプライマリであるリースを現在保持しているポッドをレポートします。

NAME              HOLDER              AGE
cluster-example   cluster-example-1   5m

有効なリース期間や最後の更新時刻を含む全体像を得るには、次を使用します。

kubectl get lease cluster-example -o yaml

プライマリリースのチューニング

リースタイミングは.spec.primaryLease の下で公開され、ほとんどのクラスターに適した値にデフォルトで設定されます。これらは、基になるKubernetesのリーダー選択パラメーターに直接マッピングされます。

Field

Default

Description

leaseDurationSeconds

15

別のインスタンスが取得するまでのリースの有効期間。

renewDeadlineSeconds

10

プライマリが断念するまでにリースの更新を再試行し続ける期間。

retryPeriodSeconds

2

非所有者がリースの取得または更新を再試行する頻度。

releasedLeaseDurationSeconds

1

プライマリがクリーンシャットダウンでリースを解放したときに書き込まれるTTL。

例、低速または一時的に到達不能のAPIサーバーに対するクラスターの耐性を高めるには

spec:
  primaryLease:
    leaseDurationSeconds: 60
    renewDeadlineSeconds: 40
    retryPeriodSeconds: 15

警告

フェールオーバータイミングへの影響を理解する場合にのみ、これらの値を調整します。間隔が長くなると、クラスターの一時的なAPIサーバーの使用不可に対する耐性が高まりますが、正当なプロモーションが遅くなります。アドミッションWebhookによって2つの不変式が適用されます。leaseDurationSeconds は`renewDeadlineSeconds` より大きい必要があり、renewDeadlineSeconds は`retryPeriodSeconds` と`1.2` より大きい必要があります。どちらも、基になるKubernetesリーダー選挙の要件を反映しています。

注釈

leaseDurationSeconds および`retryPeriodSeconds` は、2つの異なるタイミングを制御します。突然のプライマリ損失以前のプライマリがリースを解放しなかった後、候補者は引き継ぐ前に、完全な`leaseDurationSeconds` のリースを変更せずに観察する必要があります。これが、元のプライマリがまだ生きている間に時期尚早の昇格を妨げるものです。クリーンなスイッチオーバー後、以前のプライマリがリースを解放した後、そのような待機はありません。候補者は次のポーリングで解放されたリースに気づくだけであるため、ハンドオーバーのレイテンシーは`retryPeriodSeconds` によって制限されます。 retryPeriodSeconds を下げると、APIサーバーに対するリース更新の頻度が高くなりますが、早すぎるプロモーションを防ぐテイクオーバー待機を短縮せずにスイッチオーバーが高速化されます。

注釈

プライマリインスタンスは、最初にリースを取得したときにこれらのタイミングをキャプチャします。したがって、実行中のクラスターで`.spec.primaryLease` の変更は、影響を受けるプライマリポッドが再起動した後にのみ有効になります。それまで、プライマリは最初の値を使用し続けます。

RTOとRPOのインパクト

フェイルオーバーにより、サービスが影響を受ける バックアップ頻度とRTO および/またはデータが失われる RPO が発生する場合があります。

  1. プライマリに障害が発生し始め、コントローラがフェールオーバー手順を開始する前に、転送中のクエリ、WAL書き込み、チェックポイントおよび同様の操作が失敗する場合があります。

  2. fast shutdownコマンドが発行されると、クラスターは接続を受け入れなくなるため、サービスは影響を受けますが、データは失われません。

  3. 高速シャットダウンが失敗した場合、即時シャットダウンはWAL書き込みを含む保留中のプロセスを停止します。データが失われる可能性があります。

  4. プライマリがシャットダウンしており、新しいプライマリがまだ起動していない間、クラスターはプライマリなしで動作するため、機能が低下しますが、データの損失はありません。

注釈

高速シャットダウンを制御するタイムアウトは、スイッチオーバーの場合と同様に`.spec.switchoverDelay` によって設定されます。高速シャットダウンの時間を長くすることは、RPOの観点からより安全ですが、通常のオペレーションへの復帰が遅延する可能性があり、RTOに悪影響を与えます。

スイッチオーバープロセスを説明するとき、 .spec.switchoverDelay オプションはPostgreSQLデータベースのRPOとRTOに影響を与えます。低い値に設定すると、RPOよりもRTOが優先される場合がありますが、クラスターレベルおよび/またはバックアップレベルでデータの損失が発生します。逆に、高い値に設定すると、スイッチオーバー中にアクティブなプライマリのないクラスターを長時間放置する間のデータ損失のリスクを取り除くことができます。

遅延フェイルオーバー

上記で予想されたように、 .spec.failoverDelay オプションを使用すると、プライマリが異常であると検出された後、フェイルオーバープロシージャの開始を秒単位で遅延できます。デフォルトでは、この設定は0 に設定され、フェイルオーバー手順がすぐにトリガーされます。

場合によっては、新しいプライマリへのフェイルオーバーの方が、プライマリがオンラインに戻るのを待つよりも混乱を招く可能性があります。これは、複数の層が影響を受けるダウンストリーム論理サブスクライバー、またはフェールオーバーの実行時間が予想される停止よりも長い場合、ネットワークの中断に特に当てはまります。

フェールオーバーを遅延する新しい構成オプションを有効にすることにより、短期間のネットワークまたはノードの不安定性による時期尚早のフェールオーバーを防止するメカニズムを提供します。

ノードレベルの障害の検出

プライマリをホストするノードが到達不能になるたとえば、kubeletのクラッシュまたはノードとKubernetes APIサーバー間のネットワーク分割が原因で、オペレーターはポッドのReady 条件を利用して、プライマリがもはや使用不可であると判断します。ノードが正常な間、kubeletは準備状況プローブからその状態を最新の状態に保ちます。ノードが報告を停止すると、Kubernetesノードライフサイクルコントローラは、ノードUnknown を宣言するとすぐに条件をFalse に反転するものです。

在庫のkube-controller-manager設定では、移行は--node-monitor-grace-period によって管理されますKubernetes 1.29-1.31のデフォルト40s 、1.32以降では50s に引き上げられます。そのウィンドウの後、コントローラはノードUnknown をマークし、同じモニタリングパスで、は、そのノードのポッドごとにパッチを発行して、Ready 条件を反転します。実際には、オペレーターは、ノードが到達不能になってから約 40〜55秒 、プライマリの準備ができていないことを観察します猶予期間プラス最大1つの--node-monitor-period ポーリング、デフォルト5s 。管理対象KubernetesディストリビューションGKE、EKS、AKSは、これらの値を調整する場合があります。観察されたタイミングが一致しない場合は、プロバイダーのドキュメントを参照してください。その後、フェイルオーバー手順が開始されます.spec.failoverDelay によってさらにゲートされます。

Ready 条件フリップは、部分ゾーンまたは大規模クラスターの中断中にPod _eviction_を調整するレートリミッター --node-eviction-rate 、--secondary-node-eviction-rate 、--unhealthy-zone-threshold の影響を受けません。オペレーターは、ゾーンまたはクラスター全体の状態に関係なく、コントローラーがパッチを発行するとすぐに条件反転に反応します。

Pod _eviction_到達不能ノードからの実際の削除は、別のメカニズムであり、 node.kubernetes.io/unreachable NoExecute テイントデフォルトで300s のtolerationSeconds によって駆動されます。そのタイマーは、オペレーターのフェイルオーバーの決定を支持しません。 CloudNativePGは、Ready 条件が反転するとすぐに、新しいプライマリを昇格させます。その時点で、分離ノードのkubeletはすでに古いPostgreSQLコンテナをローカルに停止しています。デフォルトの.spec.probes.liveness.isolationCheck.enabled: true では、インスタンスマネージャーはAPIサーバーにもクラスターの残りの部分にも到達できず、独自のlivenessプローブに失敗し、kubeletはkills約3つのプローブ期間~30s 内のコンテナ。完全な高可用性オペレーターによる正常なノードでの古いプライマリの再作成は、実際にポッドを削除するテイントベースのエビクションでゲートされています。

Failover Quorum クォーラムベースのフェールオーバー

フェールオーバークォーラムは、CloudNativePG管理のPostgreSQLクラスターでのフェールオーバーイベント中のデータの耐久性と安全性を強化するメカニズムです。

クォーラムベースのフェールオーバーにより、コントローラーは、レプリカのクォーラムの状態に基づいて、レプリカをプライマリにプロモートせるかどうかを決定します。これは、 同期レプリケーションを介したゼロデータ損失クラスター およびデフォルトの自動フェイルオーバープロシージャが提供するものよりも強力なデータの耐久性が必要な場合に役立ちます。

同期レプリケーションが有効になっていない場合、レプリカは昇格時にプライマリよりも遅延する場合があるため、フェールオーバー中にある程度のデータ損失が予想され受け入れられます。

同期レプリケーションが有効になっている場合、保証は、必要なすべての同期スタンバイがWALデータを安全に受信したことが判明するまで、アプリケーションがトランザクションの成功したコミットの明示的な確認を受け取らないことです。これは、オペレーターが最新のレプリカをプロモーションできることを保証するのに十分ではありません。

たとえば、同期レプリケーションがANY 1 (...) に設定されている3ノードクラスターでは、コミットが確認される前にデータがプライマリと1つのスタンバイに書き込まれます。プライマリとアラインメントされたスタンバイの両方が使用不可になる場合ネットワーク分割中など、残りのレプリカには最新のデータがない場合があります。それを昇格させると、アプリケーションがコミットしたと考えられる一部のデータが失われる可能性があります。

クォーラムベースのフェイルオーバーは、オペレーターがプロモートするインスタンスに同期コミットされたデータの存在を確認できる場合にのみフェイルオーバーが発生し、それ以外の場合は発生しないようにすることにより、このリスクに対処します。

この機能を使用すると、ユーザーはデータの耐久性とデータの可用性の間で好みのトレードオフを選択できます。

.spec.postgresql.synchronous.failoverQuorum フィールドをtrue に設定することにより、フェールオーバークォーラムを有効にできます。

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3

  postgresql:
    synchronous:
      method: any
      number: 1
      failoverQuorum: true

  storage:
    size: 1Gi

下位互換性のため、古いアノテーション alpha.cnpg.io/failoverQuorum は引き続きアドミッションWebhookでサポートされ、 Cluster 仕様オプションより優先されます。

  • アノテーションが"true" と評価され、同期レプリケーションスタンザが存在する場合、Webhookは自動的に.spec.postgresql.synchronous.failoverQuorum をtrue に設定します。

  • アノテーションが"false" と評価された場合、機能は常に無効になります

注釈

アノテーションは仕様をオーバーライドするため、この実験機能のユーザーはネイティブの`.spec.postgresql.synchronous.failoverQuorum` オプションに移行し、マニフェストからアノテーションを削除することをお勧めします。アノテーションは**非推奨**であり、将来のリリースでは削除される予定です。

仕組み

レプリカをプライマリに昇格する前に、オペレーターはDynamo R + W > N 一貫性モデル[^1]の原則に従って、クォーラムチェックを実行します。

クォーラムフェイルオーバーでは、これらの値は次の意味を想定しています。

  • R は、_プロモテーブルレプリカ_読み取りクォーラムの数です。

  • W は、 COMMIT がクライアント書き込みクォーラムに返される前に、書き込みを確認する必要があるレプリカの数です。

  • N は、同期している可能性のあるレプリカの合計数です。

_プロモーブルレプリカ_は、次のプロパティを持つレプリカです。

  • クラスターの一部です。

  • 自分の状態をオペレーターに報告できます。

  • 潜在的に同期しています。

R + W > N の場合、プロモートブルレプリカの中に、すべての同期コミットを確認した少なくとも1つがあることを確認でき、安全にプライマリに昇格できます。これに当てはまらない場合、コントローラはレプリカをプライマリにプロモートせず、状況が変化するまで待機します。

クォーラムチェックが失敗した場合でも、ユーザーはkubectl cnpg promote コマンドを使用してレプリカをプライマリに強制的にプロモーションできます。

警告

手動プロモーションは最後の手段としてのみ使用してください。続行する前に、データ損失のリスクを十分に理解し、アプリケーションの書き込みワークロードの再開を優先した場合の影響を注意深く検討してください。

追加のCRDは、クラスターのクォーラム状態を追跡するために使用されます。クォーラムフェイルオーバーが有効になったCluster には、 Cluster リソースと同じ名前のFailoverQuorum リソースがあります。 FailoverQuorum CRは、クォーラムフェイルオーバーが有効になっているときにコントローラによって作成され、調整ループ中にプライマリインスタンスによって更新され、クォーラムチェック中にオペレーターによって読み取られます。これは、同期レプリケーションの最新の既知の構成を追跡するために使用されます。

注釈

ユーザーは`FailoverQuorum` リソースを直接変更しないでください。 PostgreSQLの構成の変更中に、構成を決定できない場合、FailoverQuorum リソースがリセットされ、新しい構成が適用されるまでフェイルオーバーを防止します。

FailoverQuorum リソースは、PostgreSQL同期レプリケーションと連携して動作します。

警告

クライアントに返されたが、同期的に実行されていない`SET synchronous_commit TO local` で同期レプリケーションを明示的に無効にして作成された操作など、同期的に実行されていない`COMMIT` 操作が昇格したレプリカに存在するという保証はありません。

クォーラムフェイルオーバーの例

次のシナリオでは、 R はプロモーブルレプリカの数、W はコミット前に書き込みを確認する必要があるレプリカの数、およびN は潜在的な同期レプリカの合計数です。 「Failover」列は、クォーラムフェールオーバールールでフェールオーバーが許可されるかどうかを示します。

シナリオ13ノードクラスター、障害のあるポッド

instances: 3 、synchronous.number=1 、およびdataDurability=required を含むクラスター。

  • プライマリにのみ障害が発生した場合、2つのプロモーション可能なレプリカが残りますR=2。 R + W > N (2 + 1 > 2)以降、フェイルオーバーが許可され安全です。

  • プライマリと1つのレプリカの両方に障害が発生した場合、1つのプロモートブルレプリカR=1のみが残ります。 R + W = N 1 + 1 = 2ため、データ損失の可能性を防ぐために、フェイルオーバーは許可されません。

R

W

N

Failover

2

1

2

OK

1

1

2

NO

シナリオ23ノードクラスター、ネットワークパーティション

instances: 3 、synchronous.number: 1 、およびdataDurability: required を含むクラスターでネットワークパーティションが発生します。

  • オペレーターがプライマリと通信できる場合、フェールオーバーは発生しません。プライマリがスタンバイに到達できない場合、クラスターは同期レプリケーション要件によりトランザクションをコミットしないため、クラスターは影響を受ける可能性があります。

  • オペレーターがプライマリに到達できないが、両方のレプリカR=2に到達できる場合、フェールオーバーは許可されます。オペレーターが1つのレプリカR=1のみに到達できる場合、同期的なものは別のレプリカである可能性があるため、フェールオーバーは許可されません。

R

W

N

Failover

2

1

2

OK

1

1

2

NO

シナリオ35ノードクラスター、ネットワークパーティション

instances: 5 、synchronous.number=2 、およびdataDurability=required を含むクラスターでネットワークパーティションが発生します。

  • オペレーターがプライマリと通信できる場合、フェールオーバーは発生しません。プライマリが少なくとも2つのスタンバイに到達できない場合、同期レプリケーション要件のためにトランザクションをコミットしないため、クラスターは影響を受ける可能性があります。

  • オペレーターがプライマリに到達できないが、少なくとも3つのレプリカR=3に到達できる場合、フェールオーバーは許可されます。オペレーターが2つのレプリカR=2のみに到達できる場合、同期的なものがもう一方である可能性があるため、フェールオーバーは許可されません。

R

W

N

Failover

3

2

4

OK

2

2

4

NO

シナリオ4リモート同期レプリカを使用した3ノードクラスター

instances: 3 とstandbyNamesPre またはstandbyNamesPost で定義されたリモート同期レプリカを含むクラスター。プライマリに障害が発生していると仮定します。

このシナリオでは、重要な考慮事項が必要です。 standbyNamesPre またはstandbyNamesPost にリストされているレプリカは、R ではカウントされません昇格することはできませんが、 N に含まれます同期書き込みを受信した可能性があります。したがって、 synchronous.number <= len(standbyNamesPre) + len(standbyNamesPost) の場合、ローカルレプリカが必要なデータを持つことを保証できないため、フェイルオーバーは不可能です。オペレーターは検証中にこのような構成を防止しますが、明確にするためにいくつかの無効な構成を以下に示します。

構成例

構成1有効

instances: 3
postgresql:
  synchronous:
    method: any
    number: 2
    standbyNamesPre:
      - angus

この構成では、プライマリに障害が発生すると、 R = 2 ローカルレプリカ、W = 2 、およびつのローカルレプリカ+1つのリモートでフェールオーバーが可能になります。追加のレプリカに障害R = 1 が発生した場合、フェイルオーバーは許可されません。

R

W

N

Failover

3

2

4

OK

2

2

4

NO

構成2無効

instances: 3
postgresql:
  synchronous:
    method: any
    number: 1
    maxStandbyNamesFromCluster: 1
    standbyNamesPre:
      - angus

この構成では、 R = 2 ローカルレプリカ、W = 1 、およびローカルレプリカ+1リモート。この設定ではフェールオーバーは不可能であるため、この構成ではクォーラムフェールオーバーを有効にできません。

R

W

N

Failover

1

1

2

NO

構成3無効

instances: 3
postgresql:
  synchronous:
    method: any
    number: 1
    maxStandbyNamesFromCluster: 0
    standbyNamesPre:
      - angus
      - malcolm

この構成では、 R = 0 ローカルレプリカ、W = 1 、およびローカルレプリカ+2リモート。この設定ではフェールオーバーは不可能であるため、この構成ではクォーラムフェールオーバーを有効にできません。

R

W

N

Failover

0

1

2

NO

シナリオ53ノードクラスター、優先データ耐久性、ネットワークパーティション

ネットワークパーティションが発生したinstances: 3 、synchronous.number=1 、およびdataDurability=preferred を含むクラスターを検討します。

  • オペレーターがプライマリとAPIサーバーの両方と通信できる場合、プライマリは動作を継続し、到達不能なスタンバイをsynchronous_standby_names セットから削除します。

  • プライマリがオペレーターまたはAPIサーバーに到達できない場合、クォーラムチェックが実行されます。プライマリは新しい構成を受信できないため、 FailoverQuorum ステータスは変更されることはできません。オペレーターが両方のレプリカに到達できる場合、フェイルオーバーが許可されます R=2 。 1つのレプリカR=1 のみが到達可能である場合、フェイルオーバーは許可されません。

R

W

N

Failover

2

1

2

OK

1

1

2

NO

^1