このエントリは以下のエントリをベースにしています。
This entry is based on the following written by Dmitry Kornilov.
https://dmitrykornilov.net/2019/04/17/helidon-flies-faster-with-graalvm/
GraalVMはOracle Labsが開発した高性能なオープンソースのPolyglot仮想マシンです。GraalVMは複数の機能を有しており、その中にJavaコードをAhead of Timeコンパイルしてネイティブ実行バイナリにする機能があります。バイナリはJavaランタイムを必要とせず、OS上でネイティブに動作します。
GraalVM
https://www.graalvm.org/
ネイティブ実行機能により、重要な便益がもたらされます。短時間での起動ならびにメモリフットプリントの削減、さらにコンテナ内でネイティブ実行コードを動作させる場合、コンテナイメージにJavaランタイムを含まないため、(同じJavaアプリケーションをこれまでのJVMで動作させる場合に比較して) コンテナイメージのサイズが小さくなります。最適化されたコンテナのサイズはクラウドにアプリケーションを展開する上で重要です。
Helidon 1.0.3からGraalVMのネイティブイメージ機能をサポートするようになりました。これでHelidonアプリケーションをネイティブ実行イメージとしてコンパイルし、前述のメリットを享受できるようになりました。例えば、このエントリで紹介するサンプルアプリケーションの起動時間は0.1msec、macOS上での実行ファイルのサイズは21MBでした。これらの数値はこれまでのJVMを使っている場合よりもよい結果です。
対して、すべてのものごとにはトレードオフがあります。JVM上で長時間実行するアプリケーションはランタイム最適化のおかげでGraalVMのネイティブ実行イメージより高パフォーマンスです。ここでのキーワードは長時間実行(long-running)で、短時間実行(short-running)するアプリケーション、例えばserverless functionのようなものはネイティブ実行によって性能面でのメリットを享受できます。それゆえ、高速な起動時間と小さなイメージサイズ(そしてネイティブ実行イメージ作成に必要な追加のステップ)を求めるのか、それとも長時間実行するアプリケーションでの性能を求めるのか、自問自答し結論を出す必要があります。
ネイティブバイナリへのコンパイルにあたり、アプリケーションに一定の制約が加わります。ネイティブコンパイルのため、リフレクションを使っているコード内のすべてのポイントを識別する必要があり、CDIランタイムインジェクションを使っているコードでは利用できません。Helidon MPはMicroProfile標準をサポートしており、この標準ではCDI 2.0を必要としていますし、Helidon CDI Cloud ExtensionsはCDIプラグインとして実行されています。Helidon MPでユーザー体験を制限したり複雑にしたりしたくはありませんので、Helidon SEでのみ
GraalVMをサポートします。Helidon SEは小さな、リアクティブマイクロサービスを構築するために設計されているため、ちょうどよいのです。依存性の注入や注釈、その他そういった魔法は使いません。すべてのHelidon SEの機能とコンポーネント(WebServer Config、Security、Metrics、Health Checks)はGraalVMネイティブイメージと互換性があります。
Helidonは2個の便利なGraalVMプロファイルをサポートします。
- local profile:GraalVMをローカル環境にインストールしており、ローカル環境と同じOS上で動作するネイティブ実行イメージをビルドしたい人向け
- Docker profile:GraalVMをローカル環境にインストールしていない人、もしくはローカルではmacOSを使っているものの、Linux用のネイティブ実行イメージをビルドしたい人向け
最終リリースまでにGraalVMに後方互換性のない変更が行われる可能性があるため、HelidonでのGraalVMのサポートは実験的なものです。GraalVMバージョンRC13でテスト済みです。 他のGraalVMバージョンで動作することは保証されていません。
GraalVM Community Edition 1.0 RC13
https://github.com/oracle/graal/releases/tag/vm-1.0.0-rc13
HelidonにはQuickStartのサンプルがあるので、これを使ってみましょう。このアプリケーションをHelidon on GraalVMアプリケーションのテンプレートとして利用することもできます。
Guides — Quickstart SE
https://helidon.io/docs/latest/#/guides/02_quickstart-se
Mavenのachetypeを使ってプロジェクトを生成します。
mvn archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=io.helidon.archetypes \
-DarchetypeArtifactId=helidon-quickstart-se \
-DarchetypeVersion=1.0.3 \
-DgroupId=io.helidon.examples \
-DartifactId=helidon-quickstart \
-Dpackage=io.helidon.examples.quickstart
ローカルプロファイルを使ってビルドするには、GraalVMをダウンロード、展開して展開先を環境変数GRAALVM_HOMEに設定する必要があります。
macOSを使っている場合、以下のようにGRAALVM_HOMEはGraalVMのルート内の <展開先>/Contents/Homeディレクトリを指し示している必要があります。
export GRAALVM_HOME=~/graalvm-ce-1.0.0-rc13/Contents/Home
プロジェクトをビルドして…
mvn package -Pnative-image
実行しましょう。
./target/helidon-quickstart
Dockerプロファイルを使いたい場合、GraalVMのインストールは必要ありません。以下のコマンドでDockerイメージを作成できます。
docker build -t helidon-native -f Dockerfile.native .
実行は以下のように。
docker run --rm -p 8080:8080 helidon-native:latest
Helidonはマイクロサービス用にゼロから作り上げたJavaのフレームワークであり、小さく効率的なJavaアプリケーションを作成するために必要なすべてのものを提供しています。HelidonはreactiveとMicroProfileをサポートするimperative(命令型)の2種類のプログラミングモデルを用意しています。
With GraalVMのサポートが加わり、Helidonはクラウドネイティブなマイクロサービスを開発するためのベストなソリューションの一つになりました。
ぜひHelidonオープンソースコミュニティに参加してください。ユーザーのみなさまからの質問やみなさまへのサポートをするための準備ができています。お気軽にどうぞ。
Resources
- GitHub
https://github.io/oracle/helidon - Webサイト
https://helidon.io/ - Twitter
https://twitter.com/helidon_project - Public Slackチャネル
https://helidon.slack.com/