Skip to main content

Spring Native anyone?

Fast moving world
Technologie

Spring Native anyone?

24 February 2022 - reading time: 
4
 min.

Als je een Spring Initializr start, kan je ondertussen ook de experimentele dependency spring-native selecteren.  Ook via Intellij kan je ondertussen hetzelfde doen.

Zonder in detail te treden in deze blog, kijken we even hoe we dit kunnen aanpakken en hoe snel alles opgezet is.

Laten we vlug een project opstarten soortgelijk aan het artikel dat we aan Quarkus gewijd hebben:  e en eenvoudige RestController met een GetMapping, die de befaamde "Hello World" als resultaat teruggeeft.

Intellij - Spring Initializr

Spring Boot default vs native

Als we deze spring boot applicatie opstarten dan krijgen we de standaard Spring Boot molen die zich in gang zet en na een slordige 3 seconden, is onze eenvoudige applicatie opgestart.

Started SpringNativeApplication in 2.779 seconds (JVM running for 3.134)

Nu laten we deze applicatie eens native compilen en zien hoeveel opstartkost we effectief winnen.  Om dit te kunnen doen, gaan we gebruik maken van SDKMAN, zodat we snel van JDK's kunnen wisselen.  Om native te compilen kunnen we gebruik maken van bijvoorbeeld GraalVM of de door spring zelf aangeprezen Liberica JDK.  Laten we in dit geval de marketing machine volgen en gebruik maken van de Liberica NIK Utility.  De NIK staat overigens voor Native Image Kit en is gebaseerd op... jawel, GraalVM.

Kijk zeker ook even naar het artikel ivm SDKMAN, wat het ding installeren en gebruiken een fluitje van een cent maakt.

Het volgende commando geeft ons alvast de nodige informatie welke versie we kunnen installeren.

sdk list java | grep "Liberica NIK" -A5

Aangezien we met jdk 17 werken, kiezen we voor versie 21.3.0.r17.

Na een sdk install en sdk use is onze versie in gebruik.

Nu aangezien we reeds gebruik maakte van Spring Initializr is er in onze pom.xml reeds een profile voorzien die het mogelijk maakt om de boel native te compilen.

Na het uitvoeren van "mvn clean -Pnative -DskipTests package" vinden we dan een executable terug die native gecompileerd is.  Laten we deze even uitvoeren en het effect zien.

Started SpringNativeApplication in 0.062 seconds (JVM running for 0.064)

Wat een verschil!

Docker Native Image

Laten we vervolgens een image bouwen via het commando

mvn clean -Pnative -DskipTests package spring-boot:build-image

Via Spring Initializr is er ook een Native Buildpack klaargezet in de pom.  Deze kan je terugvinden via de environment variable BP_NATIVE_IMAGE

Opgelet: Tijdens het builden konden we wel eens een creator error krijgen zonder een echte reden te vinden in de stacktrace. Bijvoorbeeld:

Building image failed with exit code: 137 of 145

Meestal komt dit door een error van de docker daemon zelf.  Zorg er zeker voor dat je Docker daemon over genoeg geheugen beschikt en verhoog ook de Xmx setting in de MAVEN_OPTS indien nodig.  In ons geval werd zo de error ook verholpen.

export MAVEN_OPTS="-Xmx4096m"

Zowel maven als de docker daemon kregen in ons geval 4 GB toebedeeld.

Dat het proces geheugenintensief is, zien we verschillende malen terugkomen als volgt:

GC warning: 19.0s spent in 16 GCs during the last stage, taking up 61.37% of the time.
[INFO]     [creator]                 Please ensure more than 3.25GB of memory is available for Native Image
[INFO]     [creator]                 to reduce GC overhead and improve image build time.

Als we nu onze container opstarten, zal je inderdaad vliegensvlug je container zijn opstarten met je spring boot applicatie erin.  Dit alles in een fractie van een seconde!

docker run -p8080:8080 spring-native:0.0.1-SNAPSHOT 
2022-02-24 13:09:52.401  INFO 1 --- [           main] o.s.nativex.NativeListener               : AOT mode enabled
...
2022-02-24 13:09:52.428  INFO 1 --- [           main] b.o.s.SpringNativeApplication            : Started SpringNativeApplication in 0.037 seconds (JVM running for 0.039)

 

We kunnen niet wachten tot de eerste final release voor handen is!