GraalVM は Java アプリケーションをスタンドアロンのネイティブイメージバイナリにコンパイルし、コールドスタートの遅延をなくし、ランタイムのメモリ使用量を削減します。ネイティブイメージは JVM をバイパスするため、ランタイムにバイトコードを変更する従来の Java エージェントは機能しません。
Application Real-Time Monitoring Service (ARMS) は、静的インスツルメンテーションでこの問題に対処します。通常はランタイムに適用されるバイトコードの変更を、静的コンパイルのステップで適用します。その結果、トレースとメトリック収集が組み込まれたネイティブイメージバイナリが生成され、ランタイムエージェントは不要になります。
ARMS における GraalVM のサポートは最先端の機能です。まずテスト環境にデプロイしてください。テクニカルサポートについては、DingTalk グループ (ID: 80805000690) にご参加ください。
制限事項
ご利用のアプリケーションは、静的コンパイルと互換性がある必要があります。Spring Boot アプリケーションについては、「Spring Boot ネイティブイメージガイド」をご参照ください。
静的コンパイルでは、ARMS が提供する GraalVM JDK を使用する必要があります。
GraalVM には、静的コンパイルのための特定の環境要件があります。「GraalVM の前提条件」をご参照ください。
ARMS は、GraalVM アプリケーションに対してトレースとメトリック監視を提供します。以下の機能はサポートされていません:
Arthas 診断
継続的診断
メモリスナップショット
GraalVM ネイティブイメージは標準の JVM アプリケーションとは異なるメモリモデルを使用するため、メタデータの詳細、非ヒープメモリ、ダイレクトバッファに関する JVM モニタリングデータは利用できません。
仕組み
統合は 5 つのステップで行います:
依存関係のインストール -- ARMS エージェント、ARMS が提供する GraalVM JDK、および Maven をダウンロードします。
Maven 依存関係の追加 -- ARMS ネイティブエージェントの依存関係と native-maven-plugin を
pom.xmlに追加します。アクセスフィルターファイルの追加 --
access-filter-file.jsonを作成し、JVM 起動クラスをリフレクション収集から除外します。アプリケーションの事前実行 -- ARMS エージェントをアタッチしてアプリケーションを実行し、エージェントが静的コンパイルに必要な動的構成を収集できるようにします。
ネイティブイメージのコンパイル -- 静的コンパイルされたバイナリをビルドして実行します。
前提条件
開始する前に、以下が準備できていることを確認してください:
GraalVM native-image の前提条件を満たす Linux 環境
GraalVM 静的コンパイル用に構成された Java アプリケーション
ARMS LicenseKey(DescribeTraceLicenseKey API オペレーションを呼び出して取得します)
手順 1:依存関係のインストール
ARMS エージェントのダウンロード
アプリケーションが実行されているリージョン用の ARMS エージェントパッケージをダウンロードします。
| リージョン | パブリックエンドポイント | VPC エンドポイント |
|---|---|---|
| 中国 (杭州) | wget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip | wget "http://arms-apm-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip |
| 中国 (上海) | wget "http://arms-apm-cn-shanghai.oss-cn-shanghai.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip | wget "http://arms-apm-cn-shanghai.oss-cn-shanghai-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip |
| 中国 (北京) | wget "http://arms-apm-cn-beijing.oss-cn-beijing.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip | wget "http://arms-apm-cn-beijing.oss-cn-beijing-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip |
| 中国 (張家口) | wget "http://arms-apm-cn-zhangjiakou.oss-cn-zhangjiakou.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip | wget "http://arms-apm-cn-zhangjiakou.oss-cn-zhangjiakou-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip |
| 中国 (深セン) | wget "http://arms-apm-cn-shenzhen.oss-cn-shenzhen.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip | wget "http://arms-apm-cn-shenzhen.oss-cn-shenzhen-internal.aliyuncs.com/ArmsAgentNative.zip" -O ArmsAgentNative.zip |
他のリージョンでのテクニカルサポートについては、DingTalk グループ (ID: 80805000690) にご参加ください。
パッケージを展開し、エージェントをインストールします:
unzip ArmsAgentNative.zip
cd ArmsAgentNative
sh install.shARMS GraalVM JDK のダウンロード
graalvm-java17-23.0.4-ali-1.2b.tar.gz をダウンロードして展開し、インストールを確認します:
tar -xzf graalvm-java17-23.0.4-ali-1.2b.tar.gz
graalvm-java17-23.0.4-ali-1.2b/bin/native-image --versionインストールが成功すると、以下のような出力が返されます:

Maven のインストール (任意)
Maven がすでにインストールされている場合は、このステップをスキップしてください。apache-maven-3.8.4-bin.tar.gz をダウンロードして展開します。
環境変数の設定
JAVA_HOME を ARMS GraalVM JDK に、MAVEN_HOME を Maven のインストール先に設定します。<graalvm-path> と <maven-path> を実際のディレクトリパスに置き換えてください。
export JAVA_HOME=<graalvm-path>/graalvm-java17-23.0.4-ali-1.2b
export PATH=$PATH:$JAVA_HOME/bin
export MAVEN_HOME=<maven-path>/apache-maven-3.8.4
export PATH=$PATH:$MAVEN_HOME/bin手順 2:Maven 依存関係の追加
ARMS ネイティブエージェントの依存関係と native-maven-plugin の構成を pom.xml に追加します。<dynamic-configs-path> を、ご利用のアプリケーションの動的構成ディレクトリの絶対パスに置き換えてください。
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>arms-javaagent-native</artifactId>
<version>4.1.11</version>
<type>pom</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<fallback>false</fallback>
<buildArgs>
<arg>-H:ConfigurationFileDirectories=native-configs,<dynamic-configs-path></arg>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>| プレースホルダー | 説明 | 例 |
|---|---|---|
<dynamic-configs-path> | 事前実行中に収集された動的構成ディレクトリの絶対パス | /opt/app/dynamic-configs |
手順 3:アクセスフィルターファイルの追加
アプリケーションのルートディレクトリに access-filter-file.json という名前のファイルを作成し、以下の内容を記述します:
{ "rules": [
{"excludeClasses": "sun.launcher.LauncherHelper"}
]
}このファイルは、GraalVM エージェントが sun.launcher.LauncherHelper のリフレクションメタデータを収集するのを防ぎます。これは JVM の起動クラスであり、そのリフレクションはネイティブイメージには不要です。このフィルターがないと、収集されたリフレクションが静的コンパイルエラーを引き起こします。
手順 4:アプリケーションの事前実行
静的コンパイルの前に、ARMS エージェントはアプリケーションと同時に実行され、動的構成を収集する必要があります。事前実行中、エージェントはバイトコードをインスツルメントし、後でネイティブイメージにコンパイルされる変更を記録します。
事前実行中にすべてのコアコードパスを実行する必要があります。実行スクリプトですべての RESTful エンドポイントを宣言し、エージェントが各エンドポイントをトリガーしてインスツルメントできるようにしてください。
実行スクリプトを開き、以下のパラメーターを構成します:
プレースホルダー 説明 例 <your-license-key>ARMS LicenseKey abl3f2xxx<your-app-name>ARMS でのアプリケーション名 graalvm-demo<endpoint-1>...実行する RESTful API パス /api/health /api/users /api/orders<your-port>アプリケーションの HTTP ポート 8080<target-path>コンパイルされたネイティブイメージの出力パス target/graalvm-demo<java-command>完全な java 起動コマンド -javaagent:./arms-native/aliyun-java-agent-native.jar -jar target/graalvm-demo-1.0.0.jar######## これらのパラメーターを構成します # ARMS license key。DescribeTraceLicenseKey API オペレーションを呼び出して取得します。 export ARMS_LICENSEKEY=<your-license-key> # アプリケーション名。分散アーキテクチャでは、複数のピアインスタンスが同じ名前を共有します。 export ARMS_APPNAME=<your-app-name> # 事前実行中に呼び出す RESTful エンドポイントのスペース区切りリスト。 export PS=(<endpoint-1> <endpoint-2> <endpoint-3>) # アプリケーションポート。 export PORT=<your-port> # target ディレクトリ内のネイティブイメージバイナリへのパス。 export NATIVE_IMAGE_FILE=<target-path> # ARMS エージェントでアプリケーションを起動するための Java コマンド。 export JAVA_CMD=<java-command> ########事前実行を開始して、静的コンパイル構成を収集します:
sh ArmsAgentNative/run.sh --collect --jvm --Carms
手順 5:ネイティブイメージのビルドと実行
静的コンパイルを実行します:
mvn -Pnative packageコンパイルされたアプリケーションを起動します:
sh ArmsAgentNative/run.sh --native --Carms
アプリケーションが起動すると、トレースデータとメトリックが自動的に ARMS にレポートされます。ARMS コンソールにログインし、アプリケーションが表示され、トレースデータが収集されていることを確認します。
Docker イメージのビルド
静的コンパイルされたネイティブイメージバイナリは自己完結型です。JDK を含むすべてのランタイム依存関係が含まれています。バイナリを Docker イメージに実行可能ファイルとして直接配置します。
<your-license-key> と <your-app-name> を、ご利用の ARMS LicenseKey とアプリケーション名に置き換えてください。
FROM centos:latest
WORKDIR /app
COPY ./target/graalvm-demo /app
CMD ["/app/graalvm-demo","-Darms.licenseKey=<your-license-key>","-Darms.appName=<your-app-name>"]UPX を使用したネイティブイメージの圧縮
ネイティブイメージと Java プログラムのサイズを比較する場合、Java プログラムは JDK のサポートを必要とするのに対し、ネイティブイメージは自己完結型ですべての依存関係をすでに含んでいるため、JDK は一般的に Java プログラムの一部と見なされます。
しかし、アプリケーションが大きくなるにつれて、そのネイティブイメージバイナリは元の JAR と JDK を合わせたサイズよりも大きくなることがあります。これは、アセンブリコード (ネイティブイメージ内) の情報密度が Java バイトコードよりも低く、同じロジックを表現するためにより多くのコードが必要になるためです。これにより、デプロイと転送への負荷が増加します。
UPX は、実行可能バイナリをより小さな実行可能ファイルに圧縮します。このファイルは手動での展開なしに直接実行でき、ランタイムパフォーマンスへの影響は最小限です。
例:静的コンパイルされた graalvm-demo ファイルは graalvm-demo-compressed に圧縮されます。216 MB の Spring Boot + RocketMQ の Fat JAR は、UPX を使用すると 47 MB (非圧縮サイズの 28.4%) に圧縮されるネイティブイメージを生成します。


UPX の使用
UPX をダウンロードして展開します。
圧縮コマンドを実行します:
パラメーター 説明 -9圧縮レベル (1--9)。値が大きいほどファイルは小さくなりますが、時間がかかります。 -o <output-file>圧縮された出力バイナリのパス。 <input-file>元のネイティブイメージバイナリへのパス。 $UPX_HOME/upx -9 -o <output-file> <input-file>