Ahead-of-time (AOT) caching
このガイドでは、Quarkus において OpenJDK の Ahead-of-Time (AOT) キャッシング機能を活用し、アプリケーションの起動時間を大幅に短縮する方法について説明します。
概要
JDK 24 以降、 Project Leyden により、Java アプリケーションの起動時間を大幅に短縮できる強力な AOT キャッシング機能 (JEP 483) が導入されました。 Quarkus はこれらの機能をファーストクラスでサポートしており、AOT 最適化されたアプリケーションのビルドとデプロイを容易にします。
|
Leyden AOT には JDK 24 以降 が必要です。それより古い JDK バージョンの場合、Quarkus は AppCDS にフォールバックできます (AppCDS (レガシー) を参照)。 |
クイックスタート
AOT キャッシングを有効にして Quarkus アプリケーションをビルドするには、以下のようにします。
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -DskipITs=false (1)
| 1 | ツールによって生成されたプロジェクトを使用している場合、 -DskipITs=false を追加することで統合テストが確実に実行されるようになります。 |
./gradlew build quarkusIntTest -Dquarkus.package.jar.aot.enabled=true
When enabling AOT via quarkus.package.jar.aot.enabled=true, Quarkus will automatically switch to the aot-jar JAR packaging if none is explicitly configured via quarkus.package.jar.type.
|
その後、次のコマンドでアプリケーションを実行します。
cd target/quarkus-app
java -XX:AOTCache=app.aot -jar quarkus-run.jar
cd build/quarkus-app
java -XX:AOTCache=app.aot -jar quarkus-run.jar
AOT 最適化された JAR パッケージング
Quarkus は、OpenJDK の AOT 機能と最適に動作するように設計された、専用の aot-jar パッケージングタイプを提供します。このパッケージングタイプは以下の特徴を持ちます。
-
最適な AOT クラスロードのためにアプリケーションを構成する
-
すべてのクラスロードを JDK のクラスローダーに委譲する (Leyden が現在カスタムクラスローダーをサポートしていないため、AOT を効果的に機能させるために必要です)
-
実行時のクラスパススキャンを避けるため、頻繁にアクセスされるリソース (サービスローダーファイルなど) をキャッシュする
It is not recommended to use the aot-jar packaging outside of the AOT use case, as the fast-jar packaging offers more optimizations that result in better performance compared to the aot-jar when Leyden’s AOT cache is not used.
|
AOT キャッシュの生成
AOT キャッシュの生成を有効にするには、以下のようにします。
./mvnw package -Dquarkus.package.jar.aot.enabled=true
./gradle build -Dquarkus.package.jar.aot.enabled=true
JDK 24 以降では、これにより Maven の場合は target/quarkus-app/ に、Gradle の場合は build/quarkus-app/ に app.aot ファイルが生成されます。
統合テストによるトレーニング
最適な結果を得るには、実際のアプリケーションワークロードを実行して AOT キャッシュを「トレーニング」する必要があります。 Quarkus は、このトレーニングに @QuarkusIntegrationTest テストスイートを使用できます。
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -DskipITs=false (1)
| 1 | ツールによって生成されたプロジェクトを使用している場合、 -DskipITs=false を追加することで統合テストが確実に実行されるようになります。 |
./gradlew build quarkusIntTest -Dquarkus.package.jar.aot.enabled=true
このアプローチでは、以下のようになります。
-
Quarkus がアプリケーションをビルドする
-
AOT トレーニングが有効な状態で、アプリケーションに対して統合テスト (つまり
@QuarkusIntegrationTestアノテーションが付いたテスト) が実行される -
JVM がテスト実行中にプロファイリングデータを取得する
-
最適化された
app.aotキャッシュが生成される
統合テストが本番のトラフィックをより忠実に再現しているほど、AOT キャッシュはより効果的になります。
|
このアプローチを機能させるには、統合テストをスキップしてはいけません。 ツールで生成された Maven プロジェクトでは、統合テストはデフォルトで無効になっており、ネイティブビルドの時のみ実行されます。 |
トレーニングフェーズの制御
quarkus.package.jar.aot.phase 設定プロパティーでトレーニングが行われるタイミングを制御します。
-
auto(デフォルト): Leyden AOT のためにintegration-testsを使用します -
build: ビルド中にキャッシュを生成します (トレーニングは非常に限定的ですが、ビルドは速くなります) -
integration-tests: 統合テストの実行中に生成します (より高度な最適化)。Leyden AOT の場合、これはautoと同じ効果を持ちます。
# Explicit integration test training
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=integration-tests
# Build-time only (builds faster, less optimal)
./mvnw package -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=build
# Explicit integration test training
./mvnw build quarkusIntTest -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=integration-tests
# Build-time only (builds faster, less optimal)
./mvnw build -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=build
AOT キャッシュでの実行
-XX:AOTCache JVM フラグを使用してアプリケーションを起動します。
cd target/quarkus-app
java -XX:AOTCache=app.aot -jar quarkus-run.jar
cd build/quarkus-app
java -XX:AOTCache=app.aot -jar quarkus-run.jar
|
|
Options that add modules, such as Flight Recorder
The JVM only uses an AOT cache if the application runs with the same --add-modules as the training run.
Otherwise it reports an error such as the following and starts the application without the cache:
[error][aot] Mismatched values for property jdk.module.addmods: jdk.jfr specified during runtime but not during dump time
Some JVM options add a module implicitly.
The most common one is -XX:StartFlightRecording, which adds jdk.jfr; enabling the Vector API with --add-modules=jdk.incubator.vector has the same effect.
If the application is always started with such an option, pass the corresponding --add-modules to the training run with quarkus.package.jar.aot.additional-recording-args:
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.additional-recording-args=--add-modules=jdk.jfr
./gradlew build quarkusIntTest -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.additional-recording-args=--add-modules=jdk.jfr
The check works both ways: a cache generated this way is only used when the application is started with -XX:StartFlightRecording or --add-modules=jdk.jfr, and is rejected otherwise.
A single cache cannot serve both kinds of runs.
To record only occasionally, keep the default cache and start the recording on the running application instead, which does not affect the cache:
jcmd <pid> JFR.start
手動による AOT ファイル生成
上述の通り、AOT ファイルの生成に関しては Quarkus がすべての面倒な作業を引き受けます。ただし、より細かな制御が必要な場合は、ユーザーが必要な手順を手動で実行することもできます。
aot-jar パッケージングを使用してアプリケーションをビルドするには、以下を使用します。
mvn package -Dquarkus.package.jar.type=aot-jar
./gradlew build -Dquarkus.package.jar.type=aot-jar
レコーディングモードでアプリケーションを起動するには、以下を使用します。
cd target/quarkus-app
java -XX:AOTCacheOutput=app.aot -jar quarkus-run.jar
cd build/quarkus-app
java -XX:AOTCacheOutput=app.aot-jar quarkus-run.jar
アプリケーションに負荷をかけた後、停止させます。プロセスが停止すると、 quarkus-run.jar と同じディレクトリーに app.aot が作成されていることがわかります。
詳細は [JEP 514](https://openjdk.org/jeps/514) を参照してください。
IBM Semeru
Quarkus also supports Semeru’s [Class Data Sharing](https://www.ibm.com/docs/en/semeru-runtime-ce-z/21.0.0?topic=sharing-introduction) AOT features.
AOT キャッシングを有効にして Quarkus アプリケーションをビルドするには、以下のようにします。
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -DskipITs=false (1)
| 1 | ツールによって生成されたプロジェクトを使用している場合、 -DskipITs=false を追加することで統合テストが確実に実行されるようになります。 |
./gradlew build quarkusIntTest -Dquarkus.package.jar.aot.enabled=true
When the JVM building the application and running the tests is IBM Semeru, then Quarkus will generate a shared classes cache instead of a Leyden AOT file.
その後、次のコマンドでアプリケーションを実行します。
cd target/quarkus-app
java -Xshareclasses:name=quarkus-app,cacheDir=app-scc,readonly -jar quarkus-run.jar
cd build/quarkus-app
java -Xshareclasses:name=quarkus-app,cacheDir=app-scc,readonly -jar quarkus-run.jar
コンテナイメージ
Quarkus は AOT キャッシュを含むコンテナーイメージを自動的にビルドできるため、すぐに高速な起動時間の恩恵を受けることができます。
AOT 強化されたコンテナーイメージのビルド
quarkus-container-image-jib 、 quarkus-container-image-docker 、または quarkus-container-image-podman を使用する場合。
./mvnw verify -Dquarkus.package.jar.aot.enabled=true -Dquarkus.container-image.build=true -DskipITs=false (1)
| 1 | ツールによって生成されたプロジェクトを使用している場合、 -DskipITs=false を追加することで統合テストが確実に実行されるようになります。 |
./gradlew build quarkusIntTest buildAotEnhancedImage -Dquarkus.package.jar.aot.enabled=true -Dquarkus.container-image.build=true
これにより、以下のことが行われます。
-
aot-jarパッケージングでアプリケーションをビルドする -
ベースとなるコンテナーイメージを作成する
-
AOT キャッシュをトレーニングするために統合テストを実行する
-
AOT キャッシュを含み、それを使用するように事前設定された、イメージバージョンに
-aotサフィックスが付いた新しいコンテナーイメージを作成する
コンテナーイメージエクステンションの追加
プロジェクトに以下の依存関係のいずれかを追加します。
<!-- Jib (recommended for most use cases) -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
<!-- Or Docker -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
</dependency>
<!-- Or Podman -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-podman</artifactId>
</dependency>
// Jib (recommended for most use cases)
implementation("io.quarkus:quarkus-container-image-jib")
// Or Docker
implementation("io.quarkus:quarkus-container-image-docker")
// Or Podman
implementation("io.quarkus:quarkus-container-image-podman")
要件と制限事項
-
Leyden AOT 機能には JDK 24 以降 が必要です
-
AOT キャッシュは JDK バージョン固有 です。実行時には、キャッシュの生成に使用されたものと全く同じ JDK バージョンを使用する必要があります。
-
この機能は Windows 環境ではテストされていません
設定リファレンス
ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能
Configuration property |
タイプ |
デフォルト |
|---|---|---|
Whether to automate the creation of an AOT file. Environment variable: Show more |
boolean |
|
The type of AOT file to generate If Environment variable: Show more |
|
|
Comma-separated list of additional recording arguments passed to the recording command line. For instance, may be used to enable advanced logging with: If an argument includes the Environment variable: Show more |
文字列のリスト |
|
The phase in which the AOT file should be generated. For Leyden AOT, For AppCDS and SCC, Environment variable: Show more |
|
AppCDS (レガシー)
JDK 24 未満のバージョンでは、Quarkus はフォールバックとして Application Class Data Sharing (AppCDS) をサポートしています。 AppCDS による起動の改善は Leyden AOT に比べると控えめですが、古い JDK でも動作します。
AppCDS アーカイブの生成
./mvnw package -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.type=app-cds
./gradlew build -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.type=app-cds
これにより app-cds.jsa ファイルが生成されます。