📈

サーバーレスNEGの外れ値検出機能の検証

2025/02/27に公開

はじめに

マルチリージョンに展開したCloud Runサービスの可用性向上を目指す際、片方のリージョンで障害が発生した場合に自動的に他リージョンへトラフィックを切り替える仕組みが求められます。

グローバル外部アプリケーションロードバランサを用いてCloud Runをバックエンドとする場合、従来のヘルスチェック機能は利用できません。そこで、外れ値検出機能を活用し、不健全なCloud Runインスタンスへのトラフィック流入を軽減する方法を検証してみました。

方法

  1. アプリケーションのコンテナイメージ作成
    • 健全なアプリケーション:HTTPステータスコード200を返却
    • 不健全なアプリケーション:HTTPステータスコード500を返却
  2. Cloud Runへのデプロイ
    • 東京リージョン:健全なアプリケーションをデプロイ(国内ユーザからのリクエストが初期に振り分けられるリージョン)
    • オレゴンリージョン:不健全なアプリケーションをデプロイ
  3. サーバーレスNEGの構成とロードバランサ設定
    • 各 Cloud Runサービスを含むサーバーレスNEG を作成し、グローバルロードバランサのバックエンドサービスに追加
    • バックエンドサービスで外れ値検出機能を有効化
      • 分析間隔:1秒、30秒、1分(複数パターンで検証)
      • 排除期間:1時間
      • 最大排除率:50%
      • 連続エラーしきい値:1(1件のエラーで対象のNEGを排除)
  4. リクエストの送信
    • 国内からロードバランサのIPアドレスへリクエストを送信
    • curlコマンドを使用し、一定間隔でリクエストを実施
      • 1秒ごとに1回(合計1800回)
      • 10秒ごとに1回(合計180回)

国内からのリクエストは、初期は東京リージョンの不健全なCloud Runに振り分けられますが、500エラー発生により外れ値検出が働くと、健全なオレゴンリージョンへトラフィックがシフトすることが期待されます。

結果

分析間隔1秒の場合

  1. 10秒ごとに1回(合計180回)リクエスト
    • 正常なレスポンスの返却率:114/180 ≒ 63%
    • 最後のエラー:32分後
  2. 1秒ごとに1回(合計1800回)リクエスト
    • 正常なレスポンスの返却率:1726/1800 ≒ 96%
    • 最後のエラー:26分後

分析間隔30秒の場合

  1. 10秒ごとに1回(合計180回)リクエスト
    • 正常なレスポンスの返却率:123/180 ≒ 68%
    • 最後のエラー:33分後
  2. 1秒ごとに1回(合計1800回)リクエスト
    • 正常なレスポンスの返却率:1728/1800 = 96%
    • 最後のエラー:18分後

分析間隔1分の場合

  1. 10秒ごとに1回(合計180回)リクエスト
    • 正常なレスポンスの返却率:127/180 ≒ 71%
    • 最後のエラー:29分後
  2. 1秒ごとに1回(合計1800回)リクエスト
    • 正常なレスポンスの返却率:1706/1800 ≒ 95%
    • 最後のエラー:33分後

結果のまとめ

以下は、各パターンで送信したリクエストに対するHTTP 200 (正常な応答)の割合をまとめたものです(小数点第一位で四捨五入)。

分析間隔 10秒ごとリクエスト 1秒ごとリクエスト
1秒 63% 96%
30秒 68% 96%
1分 71% 95%

全体として、500エラーは徐々に減少していく傾向が見られますが、リクエスト頻度が低い場合(10秒ごと)では改善のスピードが遅いことが分かりました。

考察

500エラーの完全回避は困難

外れ値検出機能は、不健全なバックエンドへのリクエストを減らし全体のエラー発生率を下げるための仕組みですが、ユーザに対して500エラーを完全に回避するものではありません。今回の検証では、1秒ごとのリクエスト開始から20分程度経過した時点でも、500エラーが発生していることが確認されました。

下記のGoogle Cloudのドキュメントからの引用にあるとおり、ロードバランサの各プロキシが独自に外れ値検出を行うため、エラーを完全に排除するのは難しい状況です。

外れ値検出を有効にした後でも、一部のリクエストが正常でないサービスに送信され、5XXエラーがクライアントに返される場合があることに留意します。これは、外れ値検出アルゴリズム(ロードバランシングプールからエンドポイントが除外されてプールに戻る)の結果が、ロードバランサのプロキシ インスタンスごとに独立して実行されるためです。ほとんどの場合、バックエンドサービスから受信したトラフィックは複数のプロキシインスタンスにより処理されます。したがって、正常でないエンドポイントが検出され、一部のプロキシのみによってそれが排除される可能性があり、その間、他のプロキシが同じ異常なエンドポイントにリクエストを送信し続ける可能性があります。

リクエスト数が少ない場合の課題

10秒ごとにリクエストするような低頻度の状況では、外れ値検出時のサンプル数が不足するためか、正常なレスポンスの割合が高まるまでに時間がかかることが分かりました。十分なリクエストデータが集まらない環境では、外れ値検出の効果が限定的になると考えられます。

分析間隔の調整は実際の環境に依存

今回、分析間隔を1秒、30秒、1分と変更して検証を行いましたが、今回のリクエスト頻度の条件下では大きな差異は見受けられませんでした。トラフィック量が多い場合、短い分析間隔の方が不健全なバックエンドを早期に排除でき、結果的にエラーを減少させるように思えます。しかし、実際のユースケースでは、システムの特性やトラフィックパターンに合わせた調整が必要であり、一概に最適な設定を決定するのは難しいと感じました。

まとめ

今回の検証により、トラフィックが多い場合には外れ値検出機能が一定の効果を発揮する一方、リクエスト数が少ない場合は十分なサンプルが得られず、効果が限定的であることが分かりました。また、外れ値検出はあくまでエラー率を低減するための機能であり、障害発生時に完全に健全なバックエンドへ切り替える仕組みではないため、障害時に一部ユーザへ影響が及ぶ可能性があります。完全なフェイルオーバーを実現するためには、Cloud Monitoringによる検知をトリガーとして、サーバーレスNEGをバックエンドサービスから除外するなどの仕組みを検討する必要がありそうです。

参考資料

https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja#outlier_detection
https://cloud.google.com/load-balancing/docs/negs/serverless-neg-concepts?hl=ja#outlier-detection

レスキューナウテックブログ

Discussion