「Javaは起動が遅い」の通説を覆すか?QuarkusでSpringをネイティブコンパイルしてみる

「Javaは起動が遅い」の通説を覆すか?QuarkusでSpringをネイティブコンパイルしてみる
目次

今回はRedhatが提供する Quarkus のSpringプラグインを試してみました。

「Javaは起動が遅い」

過去、他のプログラミング言語使用者に「Javaアプリケーションは起動が遅い。マリオカートで言うクッパみたいなもんだ」とよく言われていました。 この議論は泥仕合になる風体なのであまり好きではありませんが、確かにJITコンパラを備えた言語と違って、アプリケーションが利用可能になるまでに時間がかかることは事実です。 (以前と比べてもかなり高速になりました。それでも数秒かかりますよね?たぶん。)

たとえ数秒であっても、この起動時間を短縮することはかなり価値があります。仮にこれをほぼゼロにできるとすると、システムのスケーラビリティが格段に向上するからです。

そんなある日、Quarkus という画期的なライブラリが登場したのでした。

Quarkusとは

quarkus_top

Quarkus はRedhat社が提供するJavaアプリケーションをLinux上で動作するバイナリにネイティブコンパイルするライブラリです。 Quarkus のサイト上では、Kubernatesとの親和性を謳っていますが、Webアプリケーション以外にも広く活用できる場面があるでしょう。

ネイティブコンパイルする部分は GraalVM を採用しています。 GraalVM は様々なプログラミング言語をサポートしており、Ruby界隈ではRubyを爆速にしてみた TruffleRuby というのが一時期話題になりましたね。

GraalVM自体に制限はある ものの、提供される高速化メリットは大きいです。

本日のゴール

今回のゴールは以下とします。

  • Springのサンプルアプリケーションを Quarkus でネイティブコンパイルする
  • 起動にかかった時間を見てみる

なお、今回実装したリポジトリは こちら になります。

やってみる

環境構築

まずは環境構築をします。 実は Quarkus はドキュメントが比較的厚めに書かれているので、公式ドキュメントを見るだけで概ねできてしまいます。

環境構築は QUARKUS - GET STARTED を使えばできてしまいます。

ざっくりな手順としては以下になります。

  1. JDK 8をインストールし
  2. Apache Mavenをインストールし
  3. GraalVMをインストールパスを通す

なお、Gradleのプラグインも提供されていますが、Mavenのプラグインの方が動作が安定しているので、まずはMavenで試すことをオススメします。 (Gradleプラグインでトラブルシュートするのはなかなかきつかった)

プロジェクトの雛形を作成する

以下を実行すると quarkus-maven-plugin がプロジェクトの雛形を作成してくれます。

mvn io.quarkus:quarkus-maven-plugin:0.12.0:create \
    -DprojectGroupId=${プロジェクトのGroupID} \
    -DprojectArtifactId=${プロジェクトのArtifactID}
tree
.
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── docker
    │   │   ├── Dockerfile.jvm
    │   │   └── Dockerfile.native
    │   ├── java
    │   └── resources
    │       ├── META-INF
    │       │   └── resources
    │       │       └── index.html
    │       └── application.properties
    └── test
        └── java

最低限のdependencyを追記した状態で pom.xml も生成してくれるますから、これを使うのが楽ちんです。

よく見ると、2種類のDockerfileが作成されていることがわかります。 ファイルのsuffixで想像はつくと思いますが、アプリケーションをネイティブコードを実行するためのDockerfileと、コンテナ内でJVMを使って実行するためのDockerfileです。

Springをネイティブコンパイルしてみる

Quarkus が提供するエクステンションを使うことで、GraalVMがよしなにネイティブコンパイルしてくれるようです。

今回は私も普段使っているSpring frameworkをネイティブコンパイルするエクステンションがあるので追加してみます。

./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-spring-di"

これによって、実際には pom.xmlquarkus-spring-di がdependencyとして追加されるくらいでした。

余談ですが、対応しているエクステンションは list-extensions で確認ができます。HibernateやKotlinとかもありました。

./mvnw quarkus:list-extensions

ソースコードを書く

特に専用のコードを書く必要はなく、Springを使って普通にアプリケーションのコードを書きます。

コードを全て掲載すると冗長になるので、私のリポジトリ を参照してください。

アプリケーションをビルド&起動する

サンプルコードの実装が終わったら、アプリケーションをビルドして実行します。 今回はネイティブコードにコンパイルしたコードをコンテナ内で起動する方法にします。

まずは、アプリケーションをネイティブコンパイルします。

./mvnw package -Pnative -Dnative-image.docker-build=true

次にDockerfileをビルドします。

docker build -f src/main/docker/Dockerfile.native -t ${任意のタグ名} .

そしてコンテナを起動します。

docker run -i --rm -p 8080:8080 ${任意のタグ名}

起動時間やいかに!?

boot_docker

Quarkus 0.12.0 started in 0.076s. って早すぎでしょ。

まとめ

今回は Quarkus を使ってSpringアプリケーションをネイティブコンパイルして、Dockerコンテナ上で起動してみました。 サンプルアプリケーションではあるものの、これだけ起動時間が短縮されると未来を感じます。

2019/03現在では、まだ Quarkus はバージョンが 0.12.0 ですが、これからの進化が楽しみですね!

参考にさせていただいたサイト