はじめに
前回、こんな記事を書いてみたのですが、GraalVMによるNative化はどれくらい速いの?と思ったので軽く検証してみました。
SnapStart + Warmup版
このソースをベースに、X-Rayを有効にWarmupだけをだけを入れたバージョンで測定。
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
// we use the onStartup method of the handler to register our custom filter
handler.onStartup(servletContext -> {
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
});
+ PetsController controller = new PetsController();
+ controller.listPets(Optional.of(5), null);
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
1.16秒でした。
やはり、SnapStartのRetoreが結構時間かかります。
GraalVM版
次はこちらのサンプルにX-Rayを有効にしたソースで検証してみました。
1.09秒でした。
処理自体は27ミリ秒と非常に高速ですが、Initialization前の環境作成?と初期化を含めるとそこまでの大差はないですね。
SnapStart + Warmup + -XX:CompileThreshold=2 版
-XX:CompileThreshold
の説明は以下のサイトがとても分かりやすいですが、
メモリ上にローディングした.classファイルを更にNativeコードへコンパイルする回数の閾値みたいな設定です。
コールドスタート時に2回対象のメソッドを呼び出すことで、SnapStart時にNativeコード化までしてしまおう!という方法。
(1回だと毎回動的コンパイルが走って逆に遅い模様。)
が、あまり結果は変わらず。
まとめ
結論は、GraalVMによるNative化が一番高速かもしれません。
今回の検証ではクラスローディング対応をしたバージョンと大きく性能差はありませんでしたが、ダミー呼び出しによるクラスローディングは複雑な処理の場合、すべてのクラスを網羅できない場合もあるかと思います。
ただ、SpringBoot+GraalVMは未経験な私が少し触った感じですと、リフレクション周りであまり相性が良くない感じでしたので、Micronaut
などのフレームワークを使うのが最適かなと思います。