プロファイリングのコンセプト

プロファイリングとはコードの動的分析の一種です。アプリケーションの実行時にその特性をキャプチャし、この情報を使用してアプリケーションの速度と効率を改善する方法を見つけます。

これまで、プロファイリングはアプリケーション開発時にのみ実行されていました。このアプローチでは、本番環境を正確に予測できる負荷テストとベンチマークを開発できなければなりませんでした。

継続的プロファイリングとは、本番環境で実行中のアプリケーションをプロファイリングすることです。このアプローチにより、本番環境の正確な予測負荷テストとベンチマークの開発が不要になります。継続的なプロファイリングに関する調査で、その高い正確性と費用対効果が証明されています。*

Cloud Profiler は、Google Cloud で実行されるアプリケーション用に設計された継続的プロファイリング ツールです。

  • これは、オーバーヘッドが極めて少なく、本番環境に適した統計(サンプリング)プロファイラです。

  • 共通言語をサポートし、複数のプロファイル タイプを収集します。概要については、利用可能なプロファイリングの種類をご覧ください。

プロファイル データを生成するように Google Cloud アプリケーションを構成する手順は、プロファイリング エージェントを含めてサービスをリンクまたは実行する 1 回限りの簡単なプロセスです。アプリケーションがデプロイされると、プロファイリング エージェントが定期的に実行されてパフォーマンス データを収集し、そのデータが Google Cloud プロジェクトに送信されます。このプロセスの詳細については、プロファイルの収集をご覧ください。

アプリケーションのプロファイル データを収集したら、Profiler インターフェースを使用してデータを分析できます。プロファイル データの分析は通常、アプリケーション設計とプログラミング言語に関する知識に依存する反復的なプロセスです。

*Google 全体のプロファイリング: データセンターの継続的プロファイリング インフラストラクチャ継続的プロファイリング: すべてのサイクルはどこに消えたのかをお読みください。

利用可能なプロファイリングの種類

次の表では、サポートされているプロファイルの種類をまとめています。

プロファイルの種類 Go Java Node.js Python
CPU 時間 Y
ヒープ Y
割り当てられたヒープ
競合
スレッド
経過時間 Y

このセクションの残りの部分で、プロファイルの各種類について詳しく説明します。

測定時間

  • CPU 時間: CPU がコードブロックの実行に費やした時間です。

    関数の CPU 時間は、CPU が指示の実行にかけた時間を表します。CPU の待機時間や、他の命令の処理にかかった時間は含まれません。

  • 実時間(経過時間とも言います): コードブロックの実行に要した時間です。

    関数の実時間は、関数の開始から終了までの経過時間を表します。実時間には、ロックやスレッドの同期など、すべての待機時間が含まれます。コードブロックの実時間が CPU 時間より短くなることはありません。

実時間が CPU 時間よりもはるかに長い場合は、コードの待機時間が長いことを意味します。リソースのボトルネックが発生している可能性があります。

CPU 時間が実時間に近い場合、コードブロックが CPU を集中的に使用しています。つまり、実行時間のほとんどが CPU によって使用されています。CPU を集中的に使用するコードブロックが長時間実行されている場合は最適化が必要かもしれません。

ヒープ(メモリ)使用量

  • ヒープ使用量ヒープとも言います)は、プロファイルの収集時にプログラムのヒープ内に割り当てられているメモリの量です。一定期間にわたってデータが収集される他のプロファイル タイプとは異なり、このプロファイル タイプでは、単一の時点でヒープ使用量が収集されます。

  • ヒープ割り当て(割り当てられたヒープとも言いますとも言います)は、プロファイルが収集された期間中にプログラムのヒープ内に割り当てられたすべてのメモリを表します。この値には、割り当て済みで、解放され、現在使用されていないメモリも含まれます。例として、次のシーケンスを繰り返すジョブについて考えてみましょう。1 MiB を割り当て、500 ミリ秒待機してから 1 MiB を解放し、500 ミリ秒待機します。10 秒間、割り当てられたヒープ プロファイルを収集する間に、10 個が割り当てられ、10 個が解放されます。このプロファイルでは、解放された分が考慮されないため、割り当てられた 10 MiB のヒープが表示されます。割り当ての平均レートは 10 秒につき 10 MiB または 1 秒につき 1 MiB です。

ヒープ使用量をプロファイリングすることで、プログラムの非効率性やメモリリークの可能性を見つけることができます。ヒープ割り当てをプロファイリングすると、ガベージ コレクタの処理が最も多い割り当てを特定できます。

スレッド情報

スレッドを作成するアプリケーションの場合、スレッドが作成されても実際には実行されないことがあります。また、スレッドリークが発生し、作成されるスレッド数が増え続けることがあります。最初の問題が引き金になって 2 番目の問題が発生することもあります。

競合

マルチスレッド プログラムでは、共有リソースへのアクセスのシリアル化で待機時間が非常に長くなることがあります。競合の動作を理解することで、コードの設計に役立つ情報や、パフォーマンスの調整に必要な情報を得ることができます。

プロファイルの収集

プロファイラ エージェントの役割は、アプリケーションからプロファイル データをキャプチャし、このデータを Profiler API を使用して Profiler バックエンドに送信することです。プロファイルはアプリケーションのインスタンスごとに 1 つで、デプロイを一意に識別する 4 つのフィールドがあります。

  • GCP プロジェクト
  • アプリケーション名
  • アプリケーションのゾーン
  • アプリケーションのバージョン

エージェントはプロファイルをキャプチャする準備ができると、Profiler バックエンドに対して Profiler API コマンドを発行します。最も簡単なシナリオでは、バックエンドはこのリクエストを受け取るとすぐにエージェントに返信します。この返信には、キャプチャするプロファイルのタイプが指定されています。エージェントは、これに応じてプロファイルをキャプチャし、バックエンドに送信します。最後に、Profiler バックエンドによってプロファイルが Google Cloud プロジェクトに関連付けられます。これで、Profiler UI を使用してプロファイルを表示して分析できるようになります。

実際の handshake シーケンスは、前の段落の説明よりもずっと複雑です。たとえば、Profiler はプロファイル収集の準備ができているエージェントからリクエストを受け取ると、バックエンドでデータベースをチェックして、そのエージェントからのリクエストを以前に受け取ったことがあるかどうかを確認します。受け取ったことがない場合、バックエンドでエージェント情報がデータベースに追加されます。また、エージェントのデプロイ フィールドが、記録されている他のエージェントのフィールドと一致しない場合は、新しいデプロイが作成されます。

バックエンドは、平均して 1 分間隔で、各デプロイと各プロファイル タイプについて、エージェントを選択してプロファイルをキャプチャする指示を出します。たとえば、デプロイのエージェントがヒープ、経過時間のプロファイリングをサポートしている場合、1 分間に平均 2 つのプロファイルがキャプチャされます。

  • ヒープ使用量とスレッドを除くすべてのプロファイル タイプで、1 つのプロファイルは、10 秒間収集したデータを表します。

  • ヒープ使用量とスレッドのプロファイルは瞬時に収集されます。

重要な点は、エージェントはデータをキャプチャする準備ができていることを Profiler バックエンドに通知してから、キャプチャするプロファイル タイプが指定された返信をバックエンドから受け取るまでの間、アイドル状態になることです。同じデプロイで実行されているアプリケーションのインスタンスが 10 個ある場合は、10 個のプロファイリング エージェントを作成します。ただし、これらのエージェントは、ほとんどの時間アイドル状態です。10 分間で 10 個のプロファイルを作成できますが、各エージェントが受け取る返信は平均でプロファイル タイプごとに 1 つです。ただしランダム化により、実際の数は異なる場合があります。

Profiler バックエンドは Profiler API 割り当てとプロファイル デプロイ フィールドを使用して、取り込まれたプロファイルを制限します。Profiler の割り当ての表示と管理については、割り当てと上限をご覧ください。