Quarkus(GraalVM CE) vs Spring Boot(OpenJDK)

 
**検証環境**
Spring Boot,Quarkus⇒Red Hat Enterprise Linux release 8.4 (Ootpa) 4core/DELLのノートPC
JMeter⇒Windows 4core/DELLのノートPC
JavaはGraal/OpenJDKともにVer17

**GraalVMインストール**
https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.3.1/graalvm-ce-java17-linux-amd64-22.3.1.tar.gz
からダウンロード

```
[quarkus@localhost ~]$ pwd
/home/quarkus
[quarkus@localhost ~]$ ls
graalvm-ce-java17-linux-amd64-22.3.1.tar.gz
[quarkus@localhost ~]$ tar xf graalvm-ce-java17-linux-amd64-22.3.1.tar.gz
[quarkus@localhost ~]$ ls -l
合計 258236
drwxrwxr-x. 10 quarkus quarkus       201  2月 28 19:51 graalvm-ce-java17-22.3.1
```

.bash_profileへ追加
```
export GRAALVM_HOME=/home/quarkus/graalvm-ce-java17-22.3.1
export PATH=$GRAALVM_HOME/bin:$PATH
export JAVA_HOME=$GRAALVM_HOME
```

インストール後のバージョン確認
```
[quarkus@localhost ~]$ java -version
openjdk version "17.0.6" 2023-01-17
OpenJDK Runtime Environment GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13, mixed mode, sharing)
```
以降の手順は下記のGet Startedを参考にしてます。
https://quarkus.io/get-started/

```
[quarkus@localhost ~]$ curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/
Downloading JBang ...
Installing JBang...
[jbang] Adding [https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/] to /home/quarkus/.jbang/trusted-sources.json
[quarkus@localhost ~]$ curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio
[jbang] Command installed: quarkus
[jbang] Setting up JBang environment...
Please start a new Shell for changes to take effect

[quarkus@localhost ~]$ quarkus create && cd code-with-quarkus
Creating an app (default project type, see --help).
Looking for the newly published extensions in registry.quarkus.io
・・・省略・・・
[SUCCESS] ??  quarkus project has been successfully generated in:
--> /home/quarkus/code-with-quarkus
-----------
Navigate into this directory and get started: quarkus dev
```

ソースコード編集。
下記の二つの返す文字列をHelloにしただけ。
/home/quarkus/code-with-quarkus/src/main/java/org/acme/GreetingResource.java

```
package org.acme;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello";
    }
}
```
Unitテスト
/home/quarkus/code-with-quarkus/src/test/java/org/acme/GreetingResourceTest.java

```
package org.acme;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("Hello"));
    }

}
```

**ビルドとネイティブコンパイル**
約2分かかる（二回目以降）
初回だけは依存関係のダウンロードが走るのでもっと時間を要する。
```
./mvnw package -Pnative
・・・省略・・・
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 121266ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:10 min
[INFO] Finished at: 2023-02-28T20:18:00+09:00
[INFO] ------------------------------------------------------------------------
[quarkus@localhost code-with-quarkus]$ ls
README.md  mvnw  mvnw.cmd  pom.xml  src  target
```

**アプリケーション実行**
0.019sで起動した！！（Spring Bootの場合は3.51s）
```
[quarkus@localhost code-with-quarkus]$ ./target/code-with-quarkus-1.0.0-SNAPSHOT-runner
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-02-28 20:24:55,296 INFO  [io.net.uti.int.PlatformDependent] (Thread-1) Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system instability.
2023-02-28 20:24:55,303 INFO  [io.quarkus] (main) code-with-quarkus 1.0.0-SNAPSHOT native (powered by Quarkus 2.16.3.Final) started in 0.019s. Listening on: http://0.0.0.0:8080
2023-02-28 20:24:55,303 INFO  [io.quarkus] (main) Profile prod activated.
2023-02-28 20:24:55,303 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy-reactive, smallrye-context-propagation, vertx]
```

JMeterでの負荷検証
200スレッドでLoop Count300の負荷。

一回目：15637tps
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325048/4f3d5cf8-6b09-a952-d4b1-6284d02129d5.png)

二回目：17538tps
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325048/eb7ac37d-26a5-fb32-dc83-d9ab53cf20ee.png)

Spring Boot（OpenJDK17）で同じ負荷をかけると
一回目：4819tps
二回目：12067tps
三回目：17316tps
となった。
コンパイルが内部で走ればQuarkusと同等のスループット性能となるのは想定通り。
初速でスループット性能が出せるQuarkus(GraalVM CE)が際立つ結果となった。

**ps auxの結果**
上がQuarkus、下がSpring Boot
```
  PID %CPU %MEM    VSZ   RSS TTY     
25616  2.9  2.6 2425040 212620 pts/2 
26644 39.6  3.0 5688308 238568 pts/0 
```
両方とも起動直後にも関わらずCPU使用率が異なるのが？（＝Spring Boot何してるのか不明）

**まとめ**
起動直後の高スループットと起動時間の短さからコンテナ、サーバーレス、オートスケール環境でのアプリケーションに適する製品と評価している。


***
**参考**
比較対象（Spring Boot）のHello返すコントローラ
```
@RestController
@RequestMapping(path="/")
public class TestController {
    @RequestMapping(path="/hello", method=RequestMethod.GET)
    public String hello() {
        return "Hello";
    }
}
```