RIFE2 applications already launch quickly with a regular JVM thanks merely calling Java methods, lambdas and doing object instantiations at startup. There are no annotations to scan for, nor any declarations or config files to parse and resolve.
The RIFE2 v1.3.0 release introduced experimental support for GraalVM Ahead-Of-Time compilation with native-image, reducing the startup time of the bootstrap project from 177ms to an incredible 3ms.
Try it out yourself
In order to try this out, you can download the latest GraalVM JDK 19 distribution, and follow the steps to install native-image on your machine.
Next, clone the RIFE2 bootstrap project, make it your current directory and create an UberJar using Gradle.
./gradle2 uberjar
If you want to, you can first try the generated UberJar to get a feel of its performance and behavior:
java -jar app/build/libs/hello-uber-1.0.jar
The embedded Jetty server will start and in a little under 200ms you should be able to access http://localhost:8080/hello
to see a Hello World page.
Now, you create a single native executable with GraalVM using the following command:
native-image --no-fallback --enable-preview -jar hello-uber-1.0.jar
Starting that one up is even easier with the single executable that now contains everything:
./hello-uber-1.0
Microbenchmark numbers
I ran the previous instructions on my AMD Ryzen 9 5950X 16 Core 128GB dedicated Ubuntu Linux server and then called siege -c 10 -r 2000 -b http://localhost:8080/hello
to measure the performance:
These were the key points:
- application startup in 3ms
- standalone native executable size is 38MB
- using
siege
locally with a concurrency of 10 x 2000 requests, gives ~33898 trans/sec - after the test, used up 281.7MB RES and 24.8MB SHR memory, accounts for 0.2% of memory
In comparison, launching the Uber jar with the JVM on the same machine:
- application startup in 177ms
- uber jar size is 4.7MB but requires a separate JVM installation
- using
siege
locally with a concurrency of 10 x 2000 requests, gives ~44444 trans/sec - after the test, used up 1.7GB RES and 39.7MB SHR memory, accounts for 1.3% of memory
NOTE: RIFE2 support for GraalVM native-image is still in experimental. There's no solution yet to replace the features of the RIFE2 Java agent, and it's only been tested in a limited context.
Share your thoughts
I'm curious to hear how GraalVM native-image is faring for you.
What are you already using it for or what are your plans?
How could I further improve RIFE2 to better support Ahead Of Time compilation?
Feel free to connect on Mastodon or to join me on Discord, I would love to hear from you!