アプリにおけるレイテンシの増加をトラブルシューティングする

多くの場合、アプリケーションのレイテンシが増加すると、最終的に 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 サービス提供インフラストラクチャ

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

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

サービス全体に重大な影響を与える問題の詳細は、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 に送信されるリクエストが増える場合があります。