Java アプリケーションのプロファイリング
このページでは、プロファイリング データを収集し、そのデータを Google Cloud プロジェクトに送信するように Java アプリケーションを変更する方法について説明します。プロファイリングの全般的な情報については、プロファイリングのコンセプトをご覧ください。
Java のプロファイル タイプ:
- CPU 時間
- ヒープ(Java 11 または App Engine スタンダード環境が必要で、デフォルトでは無効)
- 経過時間(Java 8 App Engine スタンダード環境では使用できません)
サポートされている Java 言語バージョン:
- Java 8 または 11 以降用の HotSpot ベースの JVM(Oracle JDK と一部の OpenJDK ビルドを含む)。
サポートされているプロファイリング エージェントのバージョン:
- エージェントの最新リリースがサポートされています。一般に、1 年を超える期間が経過したリリースはサポートされません。エージェントの最新リリース バージョンを使用することをおすすめします。
サポートされているオペレーティング システム:
- Linux。Java アプリケーションのプロファイリングは、標準 C ライブラリが
glibc
またはmusl
で実装されている Linux カーネルでサポートされています。Linux Alpine カーネルに固有の構成情報については、Linux Alpine で実行するをご覧ください。
サポートされる環境:
- Compute Engine
- Google Kubernetes Engine(GKE)
- App Engine フレキシブル環境
- App Engine スタンダード環境(App Engine SDK バージョン 1.9.64 以降が必要)
- Dataproc(詳細については、Dataproc Spark ジョブおよび Hadoop の Cloud Profiler の構成をご覧ください)。
- Google Cloud の外部(追加の構成要件については、Google Cloud の外部で実行されているアプリケーションのプロファイリングをご覧ください)。
Profiler API を有効にする
プロファイリング エージェントを使用する前に、基盤となる Profiler API が有効になっている必要があります。Google Cloud CLI または Google Cloud Console のいずれかを使用して、API のステータスを確認し、必要に応じて有効にできます。
gcloud CLI
ワークステーションに Google Cloud CLI がまだインストールされていない場合は、Google Cloud CLI のドキュメントをご覧ください。
次のコマンドを実行します。
gcloud services enable cloudprofiler.googleapis.com
詳細については、gcloud services
をご覧ください。
Google Cloud コンソール
-
Enable the required API.
[API が有効です] が表示されている場合、API はすでに有効になっています。そうでない場合は、[有効にする] ボタンをクリックします。
サービス アカウントに IAM ロールを付与する
Google Cloud リソースにアプリケーションをデプロイし、デフォルトのサービス アカウントを使用していて、そのサービス アカウントへのロール付与を変更していない場合は、このセクションをスキップできます。
次のいずれかを行う場合は、サービス アカウントに Cloud Profiler エージェント(roles/cloudprofiler.agent
)の IAM ロールを付与する必要があります。
- デフォルトのサービス アカウントを使用しているものの、ロール付与を変更している。
- ユーザーが作成したサービス アカウントを使用している。
- Workload Identity を使用している場合は、Kubernetes サービス アカウントに Cloud Profiler エージェントのロールを付与します。
サービス アカウントに IAM ロールを付与するには、Google Cloud コンソールまたは Google Cloud CLI を使用します。たとえば、gcloud projects add-iam-policy-binding
コマンドを使用できます。
gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
--member serviceAccount:MY_SVC_ACCT_ID@GCP_PROJECT_ID.iam.gserviceaccount.com \
--role roles/cloudprofiler.agent
前のコマンドを使用する前に、次のように置き換えます。
- GCP_PROJECT_ID: プロジェクト ID。
- MY_SVC_ACCT_ID: サービス アカウントの名前。
詳細については、プロジェクト、フォルダ、組織へのアクセスを管理するをご覧ください。
Profiler エージェントをインストールする
Compute Engine
Profiler エージェント用のインストール ディレクトリを作成します(たとえば
/opt/cprof
)。sudo mkdir -p /opt/cprof
storage.googleapis.com
リポジトリからエージェント アーカイブをダウンロードし、インストール ディレクトリに展開します。wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \ | sudo tar xzv -C /opt/cprof
GKE
Dockerfile
を変更して Profiler エージェントのインストール ディレクトリを作成し、エージェント アーカイブをダウンロードしてインストール ディレクトリに展開します。
Linux(glibc
ベースの C ライブラリ):
次のインストール コマンドを使用します:
RUN mkdir -p /opt/cprof && \
wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
| tar xzv -C /opt/cprof
Linux Alpine(musl
ベースの C ライブラリ):
次のインストール コマンドを使用します:
wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent_alpine.tar.gz \ | tar xzv -C /opt/cprof
フレキシブル環境
Google Java 8 ランタイムのベースイメージまたは Java 9 / Jetty 9 ランタイムのベースイメージを使用する場合、Profiler エージェントはプリインストールされています。エージェントのインストールに必要な追加の手順はありません。
これ以外のベースイメージの場合は、エージェントをインストールする必要があります。たとえば、下の Dockerfile
には、openjdk:11-slim
イメージを使用して Profiler エージェントをインストールするための指示が含まれており、アプリケーションの起動時に使用されるデフォルトのパラメータが定義されています。
FROM openjdk:11-slim
COPY . .
RUN apt-get update \
&& apt-get install wget \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /opt/cprof && \
wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
| tar xzv -C /opt/cprof
CMD ["java", "-agentpath:/opt/cprof/profiler_java_agent.so=OPTION1,OPTION2", "-jar", "PATH_TO_YOUR_JAR_FILE"]
この Dockerfile
を App Engine フレキシブル環境で使用するには、次の操作を行う必要があります。
OPTION1
とOPTION2
をアプリケーションに必要なエージェント構成の値に置き換えます。PATH_TO_YOUR_JAR_FILE
を jar ファイルのパスに置き換えます。Dockerfile
をapp.yaml
ファイルと同じディレクトリに配置します。app.yaml
ファイルを変更してカスタム ランタイムを指定します。詳細については、カスタム ランタイムの構築をご覧ください。
スタンダード環境
Java ランタイム環境を使用する場合、Profiler エージェントはプリインストールされているため、エージェントのインストールに必要な追加の手順はありません。Java バージョン 11 以降では、/opt/cprof
にプリインストールされています。
Google Cloud 以外
Profiler エージェント用のインストール ディレクトリを作成します(たとえば
/opt/cprof
)。sudo mkdir -p /opt/cprof
storage.googleapis.com
リポジトリからエージェント アーカイブをダウンロードし、インストール ディレクトリに展開します。wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \ | sudo tar xzv -C /opt/cprof
ダウンロード可能なエージェントのすべてのバージョンを一覧表示するには、次のコマンドを実行します。
gcloud storage ls gs://cloud-profiler/java/cloud-profiler-*
コマンドのレスポンスは次のようになります。
gs://cloud-profiler/java/cloud-profiler-java-agent_20191014_RC00.tar.gz gs://cloud-profiler/java/cloud-profiler-java-agent_20191021_RC00.tar.gz gs://cloud-profiler/java/cloud-profiler-java-agent_20191028_RC00.tar.gz
特定のバージョンのエージェントをダウンロードするには、その URL をダウンロード コマンドに渡します。たとえば、2019 年 10 月 28 日にビルドされたエージェントをダウンロードするには、次のステートメントを使用します。
wget -q -O- https://storage.googleapis.com/cloud-profiler/java/cloud-profiler-java-agent_20191028_RC00.tar.gz \
| sudo tar xzv -C /opt/cprof
エージェントのバージョンは初期化中に記録されます。
Profiler エージェントを読み込む
アプリケーションをプロファイリングするには、自身のプログラムを実行する場合と同じように Java を起動します。ただし、エージェント構成オプションを指定します。エージェント ライブラリのパスを指定し、ライブラリにオプションを渡します。
App Engine スタンダード環境の場合、エージェントは自動的に読み込まれ、構成されます。プログラムを起動するに進んで、プログラムの構成と起動を行ってください。
エージェントの構成
プロファイリング エージェントを構成するには、アプリケーションの起動時に -agentpath
フラグを指定します。
-agentpath:INSTALL_DIR/profiler_java_agent.so=OPTION1,OPTION2,OPTION3
ここで、INSTALL_DIR
はプロファイリング エージェントのパス、OPTION1
、OPTION2
、OPTION3
はエージェント構成オプションです。たとえば、前の式で OPTION1
を -cprof_service=myapp
に置き換えた場合は、サービス名を myapp
に設定します。オプションの数や順序に制限はありません。サポートされている構成オプションは次のとおりです。
エージェント オプション | 説明 |
---|---|
-cprof_service
|
アプリケーションが App Engine で実行されていない場合、この構成オプションを使用してサービス名を設定する必要があります。サービス名の制限については、サービス名とバージョンの引数をご覧ください。 |
-cprof_service_version
|
サービスのバージョンごとに Profiler UI を使用してプロファイリング データを分析する機能が必要な場合は、このオプションを使用してバージョンを設定します。バージョンの制限については、サービス名とバージョンの引数をご覧ください。 |
-cprof_project_id
|
Google Cloud の外部で実行している場合は、このオプションを使用して Google Cloud プロジェクト ID を指定します。詳細については、Google Cloud の外部で実行されているアプリケーションのプロファイリングをご覧ください。 |
-cprof_zone_name
|
アプリケーションが Google Cloud で実行されている場合、プロファイリング エージェントは Compute Engine メタデータ サービスに接続してゾーンを決定します。プロファイリング エージェントがメタデータ サービスに接続できない場合は、このオプションを使用する必要があります。 |
-cprof_gce_metadata_server_retry_count -cprof_gce_metadata_server_retry_sleep_sec
|
この 2 つのオプションにより、プロファイリング エージェントが Compute Engine メタデータ サービスに接続してGCP プロジェクト ID とゾーン情報を収集するときに使用する、再試行ポリシーが定義されます。 デフォルトのポリシーでは、1 秒間待機して再試行します。最大 3 回まで再試行します。大半の構成には、このポリシーで十分です。 |
-cprof_cpu_use_per_thread_timers
|
正確な CPU 時間をプロファイリングするには、このオプションを true に設定します。このオプションを使用すると、スレッドごとのオーバーヘッドが増加します。
デフォルト値は false です。 |
-cprof_force_debug_non_safepoints
|
デフォルトで、プロファイリング エージェントは、すべてのセーフポイントのデバッグ情報だけでなく、すべてのジャストイン タイム(JIT)生成コードのデバッグ情報も JVM に生成させます。これにより、CPU 時間プロファイルとヒープ プロファイルで関数または行レベルの最も正確なロケーション情報を取得することはできますが、エージェントで追加のオーバーヘッドが発生します。このオプションを false に設定すると、JIT コードのデバッグ情報の生成を無効にできます。 デフォルト値は true です。 |
-cprof_wall_num_threads_cutoff
|
デフォルトで、アプリケーションのスレッドの合計数が 4,096 を超える場合は、経過時間プロファイルが収集されません。この上限により、プロファイルの収集中に、スレッドのスタックを走査するコストを最小限に抑えることができます。サービスに通常 4,096 を超えるスレッドがあり、追加のオーバーヘッドが発生してもプロファイリング データを収集する場合は、このフラグを使用して上限を引き上げます。 デフォルトの上限は 4,096 スレッドです。 |
-cprof_enable_heap_sampling
|
Java 11 以降でヒープ プロファイリングを有効にするには、-cprof_enable_heap_sampling=true を設定します。Java 10 以前ではヒープ プロファイリングを使用できません。ヒープ プロファイリングはデフォルトで無効になっています。 ヒープ プロファイリングを有効にすると、サンプリング間隔はデフォルトで 512 KiB に設定されます。ほとんどのアプリケーションは、この間隔で十分です。アプリケーションのオーバーヘッドは 0.5% 未満です。サンプリング間隔は 256 KiB(262144)~ 1,024 KiB(1048576)の範囲でサポートされています。たとえば、サンプリング間隔を 256 KiB に設定してサンプリング レートを 2 倍にするには、次のようにエージェント オプションを追加します。
|
サービス名とバージョンの引数
Profiler エージェントを読み込むときに、service-name 引数とオプションの service-version 引数を指定して構成します。
Profiler は、サービス名で指定されたサービスのすべてのレプリカからプロファイリング データを収集します。Profiler サービスは、サービス バージョンとゾーンの組み合わせに対して、1 つのサービス名について平均で 1 分あたり 1 個のプロファイルを作成します。
たとえば、1 つのサービスの 2 つのバージョンが 3 つのゾーンのレプリカで実行されている場合、Profiler はそのサービスについて 1 分あたり平均で 6 個のプロファイルを作成します。
レプリカで異なるサービス名を使用している場合、サービスが必要以上にプロファイリングされるため、オーバーヘッドが大きくなります。
サービス名を選択する場合は、次の点に注意してください。
アプリケーション アーキテクチャでサービスを明確に識別できる名前を選択してください。1 つのサービスまたはアプリケーションしか実行していない場合、どのようなサービス名を選択するかはさほど問題になりません。しかし、アプリケーションが一連のマイクロサービスとして実行されている場合は、名前の選択が重要になります。
service-name 文字列で、プロセス ID などのプロセス固有の値を使用しないでください。
service-name 文字列は次の正規表現と一致する必要があります。
^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$
サービス名として imageproc-service
のような静的な文字列を使用することをおすすめします。
サービス バージョンは省略可能です。サービス バージョンを指定すると、複数のインスタンスからプロファイリング情報が集約され、バージョンごとに表示されます。これは、複数のバージョンがデプロイされているときの識別に役立ちます。Profiler UI では、データをサービス バージョンでフィルタできます。これにより、コードの新旧バージョンのパフォーマンスを比較できます。
service-version 引数には、自由形式の文字列を指定できますが、通常は、バージョン番号のような値を使用します(例: 1.0.0
、2.1.2
)。
プログラムを起動する
Compute Engine
自身のプログラムを実行する場合と同じように Java を起動し、エージェント構成オプションを追加します。
java \
-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-cprof_service_version=1.0.0 \
JAVA_OPTIONS -jar PATH_TO_YOUR_JAR_FILE PROGRAM_OPTIONS
GKE
サービス コンテナの Dockerfile を変更して、自身のプログラムを実行する場合と同じように Java を起動し、エージェント構成オプションを追加します。
CMD ["java", \
"-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-cprof_service_version=1.0.0", \
"-jar", "PATH_TO_YOUR_JAR_FILE" ]
フレキシブル環境
app.yaml
構成ファイルを変更して PROFILER_ENABLE
環境変数を設定します。その後、通常どおりプログラムを起動します。
env_variables:
PROFILER_ENABLE: true
詳しくは、環境変数の定義をご覧ください。
スタンダード環境
Java 21 ランタイム環境
以前のバンドル サービスを使用していない場合は、次のいずれかの方法を使用して app.yaml
ファイルを変更し、agentpath
フラグを指定して、プロファイラ コレクションを有効にします。
-
JAVA_TOOL_OPTIONS
環境変数を設定します。runtime: java21 env_variables: JAVA_TOOL_OPTIONS: "-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true"
-
entrypoint
要素を使用してagentpath
を指定します。runtime: java21 entrypoint: java \ -agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true \ Main.java
以前のバンドル サービスを使用する場合は、次のいずれかの方法を使用して appengine-web.xml
ファイルを変更し、agentpath
フラグを指定して、プロファイラ コレクションを有効にします。
-
JAVA_USER_OPTS
環境変数を設定します。<?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <env-variables> <env-var name="JAVA_USER_OPTS" value="-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true" /> </env-variables> </appengine-web-app>
-
CPROF_ENABLE
環境変数を設定します。<?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <env-variables> <env-var name="CPROF_ENABLE" value="-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true" /> </env-variables> </appengine-web-app>
-
entrypoint
要素を使用してagentpath
を指定します。<?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <entrypoint> java -agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true </entrypoint> </appengine-web-app>
新しいプロファイル タイプが収集用に構成されている場合は、アプリケーションのデプロイ時に新しいサービス バージョンを指定します。詳しくは、特定のプロファイル タイプのデータがないのはなぜですか?をご覧ください
エージェント ロギング
プロファイリング エージェントは、App Engine フレキシブル環境、Compute Engine、GKE に関するロギング情報を報告できます。サポートされているロギングレベルは次のとおりです。
0
: すべてのメッセージをログに記録します。デフォルトのロギングレベルです。1
: 警告メッセージ、エラー メッセージ、致命的問題のメッセージをログに記録します。2
: エラー メッセージと致命的問題のメッセージをログに記録します。3
: 致命的問題のメッセージだけをログに記録してアプリケーションを停止します。
デフォルトのロギングレベルで標準エラーに記録できるようにするには、-agentpath
構成に -logtostderr
を追加します。
エラー メッセージと致命的問題のメッセージだけを記録するようロギングレベルを設定するには、-agentpath
構成に -minloglevel=2
を追加します。
たとえば、エラー メッセージと致命的問題のメッセージを標準エラーに記録できるようにするには、-agentpath
構成に -logtostderr
と ‑minloglevel=2
を追加します。
java -agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-logtostderr,-minloglevel=2 \
-jar myApp.jar
トラブルシューティング
このセクションでは、Java アプリケーションのプロファイリングに固有の問題について説明します。一般的な問題のヘルプについては、こちらのトラブルシューティングをご覧ください。
動作 | 原因 | 解決策 |
---|---|---|
複数のヒープ プロファイラを有効にしているが、プロファイル データがありません。 | 複数のヒープ プロファイラを同時に使用すると、Java のすべてのヒープ プロファイリング サポートが無効になります。これは JVM の制限です。 | 1 つのプロファイラを有効にします。 |
Linux Alpine で実行する
Linux Alpine 用の Java プロファイリング エージェントは、Google Kubernetes Engine の構成でのみサポートされています。
Linux Alpine 用の最新の Java プロファイリング エージェントをインストールするには、Profiler エージェントをインストールするをご覧ください。認証エラー
Linux Alpine で Docker イメージ(golang:alpine
や alpine
など)を使用すると、次の認証エラーが表示されることがあります。
connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"
エラーの詳細を確認するには、エージェント ロギングを有効にする必要があります。
上記のエラーは、Linux Alpine の Docker イメージに、デフォルトでインストールされているはずのルート SSL 証明書がないことを示しています。これらの証明書は、プロファイリング エージェントが Profiler API と通信するために必要になります。このエラーを解決するには、次の apk
コマンドを Dockerfile に追加します。
FROM alpine
...
RUN apk add --no-cache ca-certificates
その後、アプリケーションを再度ビルドし、デプロイする必要があります。