GraalVM

Introduction

GraalVM is a new virtual machine from Oracle that supports a polyglot runtime environment and the ability to compile Java applications to native images.

RESTHeart fully supports the GraalVM:

  • RESTHeart can be run and is supported on the GraalVM
  • Services and Interceptors can be implemented in JavaScript and TypeScript leveraging the GraalVM polyglot programming model
  • RESTHeart (and your custom plugins) can be built as a native image using GraalVM’s native-image tool

Why GraalVM

GraalVM provides advanced optimizing compiler that generates fast lean code which requires fewer compute resources and allows Ahead-of-Time Compilation to build Native binaries that start up instantly and deliver peak performance with no warm up time.

Startup time
Memory Footprint

Images from graalvm.org website.

Benefits of running RESTHeart with the GraalVM

The GraalVM is faster than OpenJDK and it is also a polyglot runtime environment, so that you can seamlessly use multiple languages to implement RESTHeart plugins.

RESTHeart leverages the GraalVM to allow developing services and interceptors using JavaScript.

See Polyglot JavaScript Services and Interceptors on GraalVM for more details.

Want to see some code? Several code examples are available as well.

Benefits of running RESTHeart as a native image

Building a RESTHeart application to native image provides multiple advantages, including faster startup time and smaller memory footprint.

A RESTHeart application is a bundle of RESTHeart core and plugins. The plugins can include the one shipped with RESTHeart (restheart-mongodb.jar and restheart-security.jar) and custom plugins that implement your application logic.

The following table compares RESTHeart (with default plugins) running on a MacBook Pro with OpenJDK, GraalVM CE and GraalVM CE native image.

  OpenJDK GraalVM CE GraalVM CE native
startup time 2441ms 2042ms 249ms
memory 487Mbyte 761Mbyte 279Mbyte
integration test execution time 63,503s 57,292s 52,518s

The numbers clearly show that running RESTHeart as a native image is ideal for microservices and clustering. With instant startup time and smaller memory footprint you can run multiple instances of RESTHeart Docker images and also better support dynamic scaling.

In some use cases, native image might result in slightly worse peak performance. Read this great article for more information. The fact that peak performances might be worse, is well compensated by the ability to run more RESTHeart instances in parallel due to much smaller memory footprint.

Install the GraalVM

We suggest to install GraalVM with sdkman

You need at least version 21.1 for Java 16:

$ sdk install java 21.1.0.r16-grl

After having installed GraalVM, you can install the native-image tool with gu

$ gu install native-image

Run RESTHeart with GraalVM

Check that GraalVM SDK is active:

$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05, mixed mode, sharing)

Then just run RESTHeart as usual:

$ java -jar restheart.jar etc/restheart.yml -e etc/default.properties

Build stock RESTHeart as native image

A Docker image of RESTHeart native is available tagged as softinstigate/restheart:<version>-native

Example:

$ docker pull softinstigate/restheart:6.0.0-native

The docker-compose-native.yml leveraging restheart-native is available as well. It runs restheart-native and MongoDB stack.

how to build from source

RESTHeart’s pom.xml includes the native profile.

Check that GraalVM SDK is active:

$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05, mixed mode, sharing)

You can then simply build it with:

$ git checkout https://github.com/SoftInstigate/restheart.git
$ cd restheart
$ mvn clean package -Pnative

As a result, you’ll find the executable binary file target/restheart-native.

Build RESTHeart with custom plugins as native image

In order to build RESTHeart with custom plugins as native image you use maven to:

At startup time, RESTHeart dynamically loads the plugins jars found in the /plugins directory. Dynamic class loading is simply not possible with GraalVM. This is why you need to package RESTHeart core and all plugins in a uber-jar and provide reflection configuration for the native-image.

uber-jar

Define the Maven native profile following this example pom.xml.

Reflection configuration

In order for the custom plugin to work, you need to define the native image reflect-config.json file in the directory src/main/resources/META-INF/native-image/<package-name>/<artifact-id>

An example is the reflect-config.json of the RESTHeart’s own test-plugins module.

For instance, the following entry is present for the Interceptor https://github.com/SoftInstigate/restheart/blob/master/test-plugins/src/main/java/org/restheart/test/plugins/interceptors/SnooperHook.java

{
    "name": "org.restheart.test.plugins.interceptors.SnooperHook",
    "methods": [
        { "name": "<init>", "parameterTypes": [] },
        { "name": "init", "parameterTypes": ["java.util.Map"] }
    ]
}

build

You can now build the native image with:

$ mvn clean package -Pnative

For further information, good starting points are:

A docker image to build Linux native images

SoftInstigate maintains the Debian based, docker image softinstigate/graalvm-maven with GraalVM and Maven and native-image.

Use it if you are running a different OS and you need to build a native image for Linux to include it in a Docker image.

$ docker pull softinstigate/graalvm-maven

You can build a Linux native image with:

$ docker run -it --rm \
    -v "$PWD":/opt/app  \
    -v "$HOME"/.m2:/root/.m2 \
    softinstigate/graalvm-maven \
    clean package -Pnative