spring-graal-nativeでSpring BootをGraalVM native imageにしてみる

この記事は、[ZOZOテクノロジーズ #4 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech4) 4日目の記事になります。
昨日は、@ikeponsu さんの「[GASでGoogleドライブ監視システムを作成](https://qiita.com/ikeponsu/items/d626f9459865ba0a85ef)」でした。

本記事では、[spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)という実験的プロジェクトを利用しSpring BootアプリケーションのGraalVM native imegeを作成し速度を比較してみました。

#はじめに
2019年11月21日に[GraalVM 19.3.0]((https://github.com/oracle/graal/releases/tag/vm-19.3.0))がリリースされましたね。
JavaプログラマーだけではなくJVMを利用している方々で、GraalVMの今後が非常に気になると思うのは私だけでしょうか？
さらに10/7-10に行われた[SpringOne Platform 2019](https://springoneplatform.io/) のセッションでは、「[Running Spring Boot Applications as GraalVM Native Images](https://www.youtube.com/watch?v=OxS66Q26ykA)」というとても興味深いセッションの動画がYouTubeにありました。内容を簡単に説明しますとSpring BootアプリケーションをGraalVMのNative Imageにする[spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)という実験的な取り組みの紹介でした。
本記事では、この動画で紹介されていた[spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)でSpring BootアプリケーションをGraalVM Native Imageにし速度を比較してみましたのでご紹介します。

#Spring Framework のGraalVM native image対応について
本題に入る前にSpring FrameworkのGraalVMの対応状況について確認しておきます。
現在の最新は[Spring Framework 5.2.1](https://github.com/spring-projects/spring-framework/releases)です。Spring Framework 5.1のときにGraalVM native imagesの初期サポートを開始しましたが問題が多くSpring Framework 5.2では問題の対応中のようです。そのためSpring FrameworkのGraalVM native image対応は、Spring framework 5.3になりそうですね。
詳細はSpring Frameworkの[GraalVM native image support Wiki](https://github.com/spring-projects/spring-framework/wiki/GraalVM-native-image-support)を参照ください。

#環境
本記事の動作確認に利用した環境はこちらです。
WSL 18.04
GraalVM CE 19.2.0.1
Spring Boot 2.2
Java8

GraalVMのWindows対応はまだGAではないので、WSLを利用して試しました。

#ダウンロード
はじめに必要なものをダウンロードします。

 - [spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)
 - [GraalVM](https://github.com/oracle/graal/releases)

まずはspring-projects-experimentalの[spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)をCloneします。
このプロジェクトはSpringの実験的なプロジェクトとなり正式版ではありません。プロダクション環境等での利用には十分ご注意ください。

```shell

$ git clone https://github.com/spring-projects-experimental/spring-graal-native.git
```

次にGraalVM 19.2.0.1をダウンロートし解凍します。
現時点での最新は19.3ですがGraalVM 19.2.0.1を利用します。
[graalvm-ce-linux-amd64-19.2.0.1.tar.gz](https://github.com/oracle/graal/releases)

```shell
$ tar -xvf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
```

#セットアップ

GraalVMのセットアップを行います。
はじめにguコマンドが使えるようにパスを通します。

```shell
$ export PATH=/home/tkani/graalvm/graalvm-ce-19.2.0.1/bin:$PATH
$ gu
GraalVM Component Updater v2.0.0

Usage:
        gu info [-clLprstuvV] <param>        prints info about specific component (from file, URL or catalog)
        gu available [-alvV] <expr>          lists components available in catalog
        gu install [-0cfiLnorvyxY] <param>   installs a component package
        gu list [-clv] <expression>          lists installed components, or components from catalog
        gu remove [-0fxv] <id>               uninstalls a component
        gu update [-x] [<ver>] [<param>]     upgrades to recent GraalVM
        gu rebuild-images                    rebuilds native images. Use -h for detailed usage
・・・・
```


guコマンドを使ってnative-imageコマンドをインストールします。

```shell
$ gu install native-image
Downloading: Component catalog from www.graalvm.org
Processing component archive: Native Image
Downloading: Component native-image: Native Image  from github.com
Installing new component: Native Image (org.graalvm.native-image, version 19.2.0.1)

$ native-image --version
GraalVM Version 19.2.0.1 CE
```

#GraalVM native imageを作成
native-imageコマンドが使えるようになったら、CloneしたSpring BootアプリケーションをGraalVM native imageにしてみます。この手順は[spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)のREADMEに記載されています。

```shell
$ cd /home/tkani/graalvm/spring-graal-native/spring-graal-native-feature
$ ./mvnw clean package
```

ここでは、commandlinerunnerディレクトリでcompile.shを実行しますが、spring-graal-native-samples配下のディレクトリには様々なプロジェクトが用意されていますね。

```shell
$ cd /home/tkani/graalvm/spring-graal-native/spring-graal-native-samples
$ ls -l
```

いよいよcompile.shを実行しGraalVM native imageを作成します。

```shell
$ cd /home/tkani/graalvm/spring-graal-native/spring-graal-native-samples
$ cd commandlinerunner
$ ./compile.sh
・・・エラー部分のみ抜粋・・・
Compiled app (clr)
./compile.sh: line 39: ./clr: No such file or directory
・・・
```

compile.shを実行するとエラーになりました。。。
調べて分かったのですが、zlib1g-devという圧縮ライブラリが必要でしたのでインストールします。

```shell
$ sudo apt install zlib1g-dev
```

こちらのブログが大変参考になりました。ありがとうございました。
[GraalVMでRust動かしたりレイトレをネイティブコンパイルしたり](https://nowokay.hatenablog.com/entry/20180422/1524417422)

#処理時間の比較
clrというGraalVM native imageができあがりましたね。
それではSpring BootのjarとGraalVM native imageの速度を比較してみましょう。

Spring Bootアプリケーションは、1.784sですね。

```shell
$ time java -jar ./target/commandlinerunner-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.0.RELEASE)

2019-12-03 14:03:26.803  INFO 1061 --- [           main] c.e.c.CommandlinerunnerApplication       : Starting CommandlinerunnerApplication v0.0.1-SNAPSHOT on ST180329 with PID 1061 (/home/tkani/graalvm/spring-graal-native/spring-graal-native-samples/commandlinerunner/target/commandlinerunner-0.0.1-SNAPSHOT.jar started by tkani in /home/tkani/graalvm/spring-graal-native/spring-graal-native-samples/commandlinerunner)
2019-12-03 14:03:26.808  INFO 1061 --- [           main] c.e.c.CommandlinerunnerApplication       : No active profile set, falling back to default profiles: default
2019-12-03 14:03:27.298  INFO 1061 --- [           main] c.e.c.CommandlinerunnerApplication       : Started CommandlinerunnerApplication in 1.12 seconds (JVM running for 1.735)
CLR running!

real    0m1.784s
user    0m3.328s
sys     0m1.156s
```

GraalVM native imageは、0.100sでした。

```shell
$ time ./clr

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::

Dec 04, 2019 12:57:58 AM org.springframework.boot.StartupInfoLogger logStarting
INFO: Starting CommandlinerunnerApplication on ST180329 with PID 1121 (/home/tkani/graalvm/spring-graal-native/spring-graal-native-samples/commandlinerunner/clr started by tkani in /home/tkani/graalvm/spring-graal-native/spring-graal-native-samples/commandlinerunner)
Dec 04, 2019 12:57:58 AM org.springframework.boot.SpringApplication logStartupProfileInfo
INFO: No active profile set, falling back to default profiles: default
Dec 04, 2019 12:57:58 AM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started CommandlinerunnerApplication in 0.044 seconds (JVM running for 0.046)
CLR running!

real    0m0.100s
user    0m0.016s
sys     0m0.078s
```

約17倍とGraalVM native imageめっちゃ早いですね！

#おわりに
GraalVMでよく話題になることで、起動は早いけど実行時はJITより遅くなるケースもあるよねって話を聞きますが、実験的なプロジェクト（ [spring-graal-native](https://github.com/spring-projects-experimental/spring-graal-native)）を用いた速度比較とは言え、この速度は非常に魅力的ですね。
Spring BootのGraalVM native image対応が正式リリースされた際は是非使ってみたいですね。

明日の[ZOZOテクノロジーズ #4 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech4) 5日目も@tkaniによる「Postmanで301リダイレクトをテストしてみる」の投稿になります。