App Engine アプリのレイテンシの増加に関するトラブルシューティング

多くの場合、アプリケーションのレイテンシが増加すると、最終的に 5xx サーバーエラーが発生します。エラーとレイテンシの急増の根本原因が同じである場合があるため、レイテンシの問題のトラブルシューティングには次の方法を適用します。

  1. レイテンシの問題の範囲を定める
  2. 原因を特定する
  3. トラブルシューティング

レイテンシの問題の範囲を定める

次のことを考慮して、問題の範囲を定義します。

  • この問題はどのアプリケーション、サービス、バージョンに影響しているか。
  • この問題はサービスのどのエンドポイントに影響しているか。
  • すべてのクライアントにグローバルに影響しているか、それとも特定のクライアントのサブセットに影響しているか。
  • インシデントの開始時刻と終了時刻はいつか。タイムゾーンを指定することを検討してください。
  • 具体的にどのようなエラーが発生しているか。
  • レイテンシにはどれほどの差分が観測されるか、特定のパーセンタイルでの増加として通常示されるものはどれか。たとえば、90 パーセンタイルでレイテンシが 2 秒増加したなどです。
  • レイテンシをどのように測定したか。具体的には、レイテンシはクライアントで測定したのか、または Cloud Logging や App Engine のサービング インフラストラクチャで提供される Cloud Monitoring のレイテンシ データで確認したのか。
  • サービスにどのような依存関係があるか、依存関係のいずれかにインシデントが発生しているか。
  • この問題を引き起こすコード、構成、ワークロードの変更を最近行ったか。

サービス独自のカスタム モニタリングとロギングを使用すると、問題の範囲をさらに絞り込むことができます。問題の範囲を定義することで、考えられる根本原因を特定し、次のトラブルシューティング手順を決定できます。

原因を特定する

リクエストパス内のどのコンポーネントがレイテンシまたはエラーの原因となっているかを判断します。リクエストパスの主なコンポーネントは次のとおりです。

クライアント --> インターネット --> Google Front End(GFE)-> App Engine サービング インフラストラクチャ --> サービス インスタンス

上記の情報で障害の原因を特定できない場合は、サービス インスタンスの正常性とパフォーマンスを確認しながら、次の方法を適用します。

  1. App Engine リクエストログをモニタリングします。これらのログに HTTP ステータス コードエラーまたはレイテンシの増加が見られた場合、サービスを実行しているインスタンスに問題がある可能性があります。

  2. サービス インスタンスの数がトラフィック レベルに合わせてスケールアップされていない場合、インスタンスが過負荷状態になり、エラーとレイテンシが増加する可能性があります。

  3. Cloud Monitoring でエラーまたはレイテンシの増加が発生している場合は、App Engine の指標を記録するロードバランサのアップストリームに問題がある可能性があります。ほとんどの場合、これはサービス インスタンスに問題があることを示しています。

  4. モニタリング指標でレイテンシの増加やエラーが見られてもリクエストログでは見られない場合は、ロード バランシングの障害か、ロードバランサによるリクエストのルーティングを妨げる重大なインスタンス障害を示しています。これらのケースを区別するには、インシデントが発生する前のリクエストログを確認します。リクエストログで障害発生前にレイテンシが増加している場合は、ロードバランサがリクエストのルーティングを停止する前にアプリケーション インスタンスで障害が発生していたことになります。

トラブルシューティング

このセクションでは、リクエストパスの次のコンポーネントによるレイテンシの増加に関する問題のトラブルシューティング方法について説明します。

  1. インターネット
  2. Google Front End(GFE)
  3. App Engine サービス提供インフラストラクチャ
  4. アプリケーション インスタンス
  5. アプリケーションの依存関係

インターネット

接続が不安定な場合や帯域幅が低い場合、アプリケーションでレイテンシの問題が発生することがあります。

インターネット接続が不安定

インターネット接続が原因になっているかどうかを確認するには、クライアントで次のコマンドを実行します。

$ curl -s -o /dev/null -w '%{time_connect}\n' <hostname>

time_connect の値は、最も近い Google Front End へのクライアント接続のレイテンシを表します。接続が遅い場合は、traceroute を使用してトラブルシューティングをさらに行い、ネットワーク上のどのホップが遅延の原因となっているかを判断します。

テストは、さまざまな地域のクライアントから行ってください。App Engine は、最も近い Google データセンターにリクエストを自動的にルーティングします。ルーティング先はクライアントのロケーションによって異なります。

低い帯域幅

アプリケーションは迅速に応答していても、ネットワークのボトルネックにより、App Engine サービング インフラストラクチャからネットワーク全体へのパケット送信に遅延が発生し、レスポンスが遅くなることがあります。

Google Front End(GFE)

ルーティングが正しくない場合、HTTP/2 クライアントから並列リクエストが送信された場合、または SSL 接続が終端した場合に、アプリケーションでレイテンシの問題が発生することがあります。

クライアント IP を地理的リージョンにマッピングする

Google は、DNS ルックアップで使用されているクライアント IP アドレスに基づいて、App Engine アプリケーションのホスト名をクライアントに最も近い GFE に解決します。クライアントの DNS リゾルバが EDNS0 プロトコルを使用していない場合、Google はクライアント リクエストを最も近い GFE にルーティングしないことがあります。

HTTP/2 ヘッドオブライン ブロッキング

複数のリクエストを並列で送信する HTTP/2 クライアントでは、GFE でのヘッドオブライン ブロッキングが原因でレイテンシが増加する場合があります。この問題を解決するには、クライアントが QUIC プロトコルを使用する必要があります。

カスタム ドメインの SSL 終端

GFE が SSL 接続を終端することがあります。appspot.com ドメインではなくカスタム ドメインを使用している場合、SSL 終端には追加のホップが必要です。これにより、一部のリージョンで動作しているアプリケーションのレイテンシが増加する可能性があります。詳細については、カスタム ドメインのマッピングをご覧ください。

App Engine サービス提供インフラストラクチャ

サービス全体のインシデントや自動スケーリングが原因で、アプリケーションのレイテンシが増加することがあります。

サービス全体のインシデント

Google は、サービス全体に重大な影響を与えるインシデントの詳細を Service Health ダッシュボードに投稿します。ただし、Google は段階的なロールアウトを行うため、サービス全体のインシデントがすべてのインスタンスに同時に影響を与えることはほとんどありません。

自動スケーリング

次の自動スケーリング シナリオでは、レイテンシの増加やエラーが発生する可能性があります。

  • トラフィックの増加が速すぎる: App Engine の自動スケーリングでは、トラフィックが増加してもインスタンスは同じ速さでスケーリングされないため、一時的に過負荷が発生することがあります。通常、過負荷は、エンドユーザーではなくコンピュータ プログラムによってトラフィックが生成された場合に発生します。この問題を解決するには、トラフィックを生成するシステムをスロットリングします。

  • トラフィックの急増: トラフィックが急増すると、レイテンシに影響を与えずに、自動スケーリングされるサービスが可能な速度よりも高速にスケールアップする必要がある場合に、レイテンシが増加することがあります。通常、エンドユーザーのトラフィックによるトラフィックの急増は頻繁には発生しません。トラフィックの急増が確認された場合は、原因を調査する必要があります。バッチシステムが一定の間隔で動作している場合は、トラフィックを平滑化するか、別のスケーリング設定を使用できることがあります。

  • オートスケーラーの設定: オートスケーラーは、サービスのスケーリング特性に基づいて構成できます。スケーリング パラメータは、次のシナリオでは最適でなくなることがあります。

    • App Engine スタンダード環境のスケーリング設定が厳しすぎると、レイテンシが発生する可能性があります。ログにステータス コード 500 と「Request was aborted after waiting too long to attempt to service your request」というメッセージを含むサーバーのレスポンスが表示された場合は、アイドル状態のインスタンスを待機している間に保留中のキューでリクエストがタイムアウトしたことを意味します。

    • 十分なインスタンスをプロビジョニングしても、手動スケーリングを使用すると保留時間が長くなることがあります。アプリケーションがエンドユーザー トラフィックを処理する場合は、手動スケーリングを使用しないことをおすすめします。手動スケーリングは、タスクキューなどのワークロードに適しています。

    • 基本スケーリングでは、レイテンシを犠牲にして費用を最小限に抑えます。レイテンシの影響を受けやすいサービスには、基本スケーリングを使用しないことをおすすめします。

    • App Engine のデフォルトのスケーリング設定では、ほとんどのサービスで最適なレイテンシが得られます。それでも保留時間の長いリクエストが見られる場合は、最小数のインスタンスを指定してください。アイドル状態のインスタンスを最小限に抑えることで費用を抑えるようにスケーリング設定を調整すると、負荷が急増した場合にレイテンシが急増するおそれがあります。

デフォルトのスケーリング設定でパフォーマンスのベンチマーク テストを行ってから、これらの設定を変更するたびに新たにベンチマークを実行することをおすすめします。

デプロイ

デプロイの直後にレイテンシが増加する場合は、トラフィックを移行する前に十分にスケールアップが行われていないことを示しています。新しいインスタンスでは、ローカル キャッシュのウォームアップが行われていないために、古いインスタンスよりも処理が遅くなることがあります。

レイテンシの急増を回避するため、サービスの既存のバージョンと同じバージョン名を使用して App Engine サービスをデプロイしないでください。既存のバージョン名を再利用すると、トラフィックを新しいバージョンに徐々に移行できなくなります。App Engine は短時間にすべてのインスタンスを再起動するため、リクエストが遅くなることがあります。以前のバージョンに戻す場合は、再デプロイも必要です。

アプリケーション インスタンス

このセクションでは、アプリケーション インスタンスやソースコードに適用できる、パフォーマンス最適化とレイテンシ低減のための一般的な戦略について説明します。

アプリケーション コード

アプリケーション コードに問題があると、特に問題が断続的に発生する場合や再現できない場合に、デバッグが困難になることがあります。

問題を解決するには、次の操作を行います。

  • 問題を診断するには、ロギングモニタリングトレースを使用してアプリケーションを計測することをおすすめします。Cloud Profiler を使用することもできます。

  • ローカル開発環境で問題を再現してみてください。それにより、App Engine では実行できない言語固有のデバッグツールを実行できる場合があります。

  • アプリケーションのエラーや発生するボトルネックについて理解を深めるには、障害が発生するまでアプリケーションの負荷テストを行います。最大インスタンス数を設定し、アプリケーションに問題が発生するまで負荷を徐々に増やします。

  • レイテンシの問題が新しいバージョンのアプリケーション コードのデプロイと相関している場合は、ロールバックして、新しいバージョンがインシデントの原因かどうかを判断します。ただし、デプロイを継続的に行うと、デプロイが頻繁に発生するため、開始時点でデプロイがインシデントの原因になったかどうかを判断することが困難になります。

  • アプリケーションは、Datastore 内などに構成設定を保存する場合があります。構成変更のタイムラインを作成することで、レイテンシの増加の開始と一致する構成変更があるかどうかを判断できます。

ワークロードの変化

ワークロードの変化により、レイテンシが増加する可能性があります。ワークロードの変化を示すモニタリング指標には、qps、API の使用状況、レイテンシなどがあります。リクエストとレスポンスのサイズの変化も確認してください。

メモリ負荷

モニタリングでメモリ使用量にのこぎり歯のようなパターンが見られる場合や、デプロイに相関してメモリ使用量の低下が見られる場合は、メモリリークがパフォーマンスの問題の原因となっている可能性があります。メモリリークによりガベージ コレクションが頻繁に発生し、レイテンシが高くなることがあります。この問題をコードの問題に帰することができない場合は、より多くのメモリを使用してより大きなインスタンスをプロビジョニングしてみてください。

リソースリーク

アプリケーションのインスタンスで、インスタンス起動からの経過時間に伴うレイテンシの上昇が見られる場合は、リソースリークの発生によってパフォーマンスの問題が引き起こされていることがあります。デプロイが完了すると、レイテンシが低下します。たとえば、CPU 使用率が高いために時間の経過とともに遅くなるデータ構造があると、CPU の制約を受けるワークロードが遅くなることがあります。

コードの最適化

App Engine のレイテンシを短縮するには、次の方法でコードを最適化します。

  • オフライン作業: Cloud Tasks を使用して、アプリケーションによるメール送信などの作業の完了待ちが、ユーザー リクエストによってブロックされないようにします。

  • 非同期 API 呼び出し: API 呼び出しの完了待ちがコードでブロックされないようにします。

  • バッチ API 呼び出し: 通常、API 呼び出しのバッチ処理は、呼び出しを個々に送信するよりも高速です。

  • データモデルの非正規化: データモデルを非正規化することで、データ永続化レイヤに対する呼び出しのレイテンシを短縮します。

アプリケーションの依存関係

アプリケーションの依存関係をモニタリングすることで、レイテンシの急増が依存関係の不具合と相関しているかを検出できます。

ワークロードの変化とトラフィックの増加により、依存関係のレイテンシが増加することがあります。

スケーリングされない依存関係

App Engine インスタンスの数がスケールアップしてもアプリケーションの依存関係がスケーリングされない場合、トラフィックが増加すると、依存関係が過負荷状態になることがあります。スケーリングされない依存関係の例として、SQL データベースがあります。アプリケーション インスタンスの数が多くなるとデータベース接続数が増え、データベースの起動が妨げられてカスケード障害が発生することがあります。この問題を解決するには、次の操作を行います。

  1. データベースに接続されない新しいデフォルト バージョンをデプロイします。
  2. 以前のデフォルト バージョンをシャットダウンします。
  3. データベースに接続する、デフォルト以外の新しいバージョンをデプロイします。
  4. トラフィックを新しいバージョンにゆっくり移行します。

予防策として、アダプティブ スロットリングを使用して依存関係へのリクエストをドロップするようにアプリケーションを設計することをおすすめします。

キャッシュ レイヤの障害

リクエストを高速化するには、エッジ キャッシュ、Memcache、インスタンス内メモリなど、複数のキャッシュ レイヤを使用します。これらのキャッシュ レイヤのいずれかの障害が原因で、レイテンシが急増する場合があります。たとえば、Memcache のフラッシュによって、より低速の Datastore に送信されるリクエストが増える場合があります。