X
May 11, 2020

Run Applications in OCI with GraalVM: Easy as Pie

By: Olga Gupalo | Member of Technical Staff

Share

Oracle GraalVM Enterprise is a high performance runtime that provides significant improvements to application execution, efficiency and security running on premise or in the cloud. In this blog post we are going to show how to get started with GraalVM Enterprise in Oracle Cloud Infrastructure (OCI) and run some workloads in the virtual host.  An important notice, if you have an ongoing subscription to Oracle Cloud, the support for GraalVM Enterprise  is included.

OCI has been one of the first adopters of  GraalVM Enterprise.  
Oracle Cloud Infrastructure Monitoring service, the health and performance monitoring metrics, first completed the move to using GraalVM in production and reported a 5% reduced CPU consumption and a 10% increase in the number of transactions per second compared to the previous JDK.

This high-performance platform can be used in the following deployment scenarios:

  • 1. OCI Bare Metal and Virtual Machines
  • 2. Oracle Containers (Oracle Kubernetes Engine)
  • 3. Oracle Functions 

Each of those deserves a separate blog post.  Further below we will focus on the first scenario, more precisely, on Virtual Machine compute instance type in OCI. We will start by setting up the GraalVM Enterprise environment and continue by running some demos. Firstly, we will run a sufficiently large Spring-based application. Secondly, we will go over a JMH benchmark to measure the performance using the GraalVM compiler versus C2.  Lastly, we will run an example written with the Micronaut framework and compile it ahead-of-time.

There are two ways to proceed with the GraalVM Enterprise installation:

  • * Automatic install in a Linux operated VM instance with the YUM utility
  • * Manual transfer of GraalVM Enterprise files from a local machine to a VM host
 

We will follow an automatic installation. For manual file transferring, check this resource. Assuming you have a VM instance in OCI up and running already. For a complete beginner,  start by creating and launching the first Linux instance tutorial.  For demonstration purposes we created a demo-instance of the VM.Standard2.1 type on the Oracle Linux 7.7 pre-built image.
oci_vm_compute_instance_console

In OCI a user can connect to an instance using a Secure Shell (SSH) or remote desktop connection.  We are going to use SSH to connect from a Unix-style system: 

ssh -i .ssh/id_rsa opc@150.136.54.68

The.ssh/id_rsa is a full path and name of the file containing the private SSH key, opc is the default name for the Oracle Linux image, and 150.136.54.68  is the instance IP address provisioned from the console. For more details, refer to the Connecting to Your Linux Instance Using SSH guide.

Since recently, Oracle GraalVM Enterprise RPMs have been made available in OCI YUM repository for the product installation convenience. That means that OCI customers can use GraalVM Enterprise environment in their cloud instances by simply installing it with yum - a package-management utility for the Linux operating systems.
Having connected to the instance, let's verify what GraalVM RPMs are available for the installation:

[opc@demo-instance ~]$ sudo yum provides graalvm*

The printed list is huge as includes previous versions, but we are looking for the latest "Oracle GraalVM Enterprise Edition JDK8 Bundle". Though it is recommended  to refresh the repo data which outdates with newer GraalVM Enterprise releases by running yum check-update.

To install GraalVM Enterprise, it is enough to run sudo yum install <package_name>. In our case it would be sudo yum install graalvm20-ee-8-20.0.0-1.el7.x86_64.

All dependent packages, .e.g,  libpolyglotllvm etc., would be resolved.  total installed size is 1.3 G which is affordable as an instance of the VM.Standard2.1 type is assigned  15 GB Memory  and 1 Core OCPU by default. Also, OCI gives you a possibility to alter the default boot volume size of 46.6 GB to maximum 32,768 GB anytime later.  

After the installation, GraalVM Enterprise binaries are placed in the root usr/lib64/graalvm directory:

[opc@demo-instance ~]$ java -version
java version "1.8.0_241"
Java(TM) SE Runtime Environment (build 1.8.0_241-b07)
Java HotSpot(TM) 64-Bit Server VM GraalVM EE 20.0.0 (build 25.241-b07-jvmci-20.0-b02, mixed mode)

For better user experience, let's set PATH and JAVA_HOME to point to the GraalVM Enterprise. Open the .bashrc profile in the VM server, nano ~/.bashrc, and copy-paste what is suggested below, save and exit the editor:

export JAVA_HOME=/usr/lib64/graalvm/graalvm20-ee-java8
export PATH=/usr/lib64/graalvm/graalvm20-ee-java8/bin:$PATH

Then run source ~/.bashrc to get these changes in the current SSH session. Now we have a ready-to-go VM instance. OCI allows to create custom images of it,  inheriting all parents environment settings:  return to the instance console, expand “Actions” drop down menu in the top menu and click “Create Custom Image".

Time to run some workloads!

We compressed all applications sources into oci-demos.zip and transferred them in one go  via the scp SSH service from our local machine to the VM host using this command:

~/Downloads$ scp -i ~/.ssh/id_rsa oci-demos.zip opc@150.136.54.68:/home/opc

If you want to repeat the examples we are going to show below, please download each separately (demo 1demo 2demo 3).
The home/opc is a default working directory.  Re-connect to the host and unzip the archive:

ssh -i .ssh/id_rsa opc@150.136.54.68
[opc@demo-instance ~]$ unzip oci-demos.zip

Demo 1

GraalVM Enterprise would work for your Java applications out of the box either on a local or virtual host.  We are going to demonstrate that using  a well-known sample Spring application - PetClinic.  To start, enter Spring PetClinic application inside the oci-demos directory, build the project with Maven and run it:

[opc@demo-instance ~]$ cd oci-demos/spring-petclinic
[opc@demo-instance spring-petclinic]$ ./mvnw package
[opc@demo-instance spring-petclinic]$ java -jar target/*.jar

To visit PetClinic in the browser,  we had to ensure that the Linux host firewall and OCI security lists are not blocking the port 8080.  Let's look into this closer. Each compute instance in OCI is attached to a Virtual Cloud Network (VCN), which in turn resides in a subnet and enables a network connection for that instance. You can think of each compute instance as residing in the subnet to which you can write a custom firewall rule in addition to the associated subnet's security lists.  Navigate to VCN address from the instance information window, then to Public Subnet and open Default Security List for the attached VCN. Press "Add Ingress Rule" and fill in the following data:  

 

Make sure the destination port is 8080.  To open a running server, substitute "localhost" with  the Public IP address assigned to the instance. If you still experience connection issues, open the port 8080 on the Linux firewall:

[opc@demo-instance ~]$ sudo firewall-cmd --permanent --add-port=8080/tcp
[opc@demo-instance ~]$ sudo systemctl reload firewalld

In our case, the application is listening on http://150.136.54.68:8080:

Demo 2

The second application we are going to run is a JMH benchmark to measure the performance using  the GraalVM Enterprise compiler and without it (using C2, the JVM default one). The benchmark creates a stream from array elements, and maps each number using several mapping functions. GraalVM Enterprise  achieves the performance improvement of between 2x and 5x on Stream programs.

The benchmark project has to be built with Maven. Unlike the previous PetClinic Spring application, this demo does not come with a Maven Wrapper (.mvnw), and Oracle Linux 7 does not include this build tool by default, we will need to add it to the system packages. Search for it in YUM repository:

[opc@demo-instance ~]$ yum search maven

Search gives multiple results. Oracle only provides the latest versions to the software collection library and only supported for the latest update of Oracle Linux 7. Having checked this resource, we can see "rh-maven35" is most recent.  Install it:

[opc@demo-instance ~]$ sudo yum install rh-maven35*

and include the following line source /opt/rh/rh-maven35/enable to your the .bashrc file. It will make Maven always available.  Enter the java-simple-stream-benchmark directory, build the benchmark project and run it.

[opc@demo-instance ~]$ cd oci-demos/java-simple-stream-benchmark 
[opc@demo-instance java-simple-stream-benchmark]$ mvn package
[opc@demo-instance java-simple-stream-benchmark]$ java -jar target/benchmarks.jar

The JavaSimpleStreamBenchmark.testMethod is executed in 3 iterations to leverage the warmup time and pick performance. The benchmark result is in nanoseconds per operation which means lower numbers are better. Now let's run this benchmark on the same JVM (GraalVM Enterprise), but without the GraalVM compiler by adding the -XX:-UseJVMCICompiler option. The GraalVM compiler will not be used as the JVMCI compiler and the JVM will use its default one: 

[opc@demp-instance java-simple-stream-benchmark]$ java -XX:-UseJVMCICompiler -jar target/benchmarks.jar

The difference in score results is quite noticeable.

 

Demo 3 

Lastly we are going to run a Micronaut application in a JVM versus as a native executable. Change to the micronaut directory, build and run the example with Gradle Wrapper:

[opc@demo-instance ~]$ cd oci-demos/micronaut
[opc@demo-instance micronaut]$ ./gradlew assemble
[opc@demo-instance micronaut]$ ./gradlew run

The application is started on port 8080 calling the Controller random() method that returns a Conference. The @Controller annotation is mapped to the path /conferences:
http://150.136.54.68:8080/conferences/random

Let's terminate the application and generate a native Linux executable with the Native Image technology of GraalVM Enterprise.  Micronaut framework itself does not rely on reflection or dynamic class loading so works well with GraalVM Native Image. Native Image comes as a separate installable so we need to add it to the base installation. Search for a proper package name with YUM and then install it:

[opc@demp-instance ~]$ yum search native-image
[opc@demp-instance ~]$ sudo yum install graalvm20-ee-8-native-image.x86_64

If you compare the content of a GRAALVM_HOME/bin directory before and after the Native Image installation ($ ls /usr/lib64/graalvm/graalvm20-ee-java8/bin), you would notice that the native-image launcher has been added.

Native Image has a dependency on libstdc++ system library. To avoid a probable image generation failure because of a missing dependency, let’s install it at first and then build a native image:

[opc@demo-instance micronaut]$ yum search  libstdc++
[opc@demo-instance micronaut]$ sudo yum install  libstdc++*
[opc@demo-instance micronaut]$ native-image --no-fallback --no-server -cp build/libs/micronaut-0.1-all.jar
[opc@demo-instance micronaut]$ ./micronaut

During application creation, we used the graal-native-image  feature, which added svm and graal dependencies in build.gradle script and wrote a native-image.properties file in resources/META-INF/native-imagedirectory with necessary configuration. Compare the application startup time when running in a JVM and as a native image!

Note, the resulting executable  is not a fallback image, you can build it on your local machine with GraalVM Enterprise distribution for Linux platforms, then transfer over  secure copy protocol (scp) SSH service to your VM host and launch. There is no JDK required to run it! This scenario is actual in cases when you have resources constrains, e.g. memory, or the processes need to start fast.

Conclusion

Fast startup time, lower memory consumption and higher maximum latency make GraalVM Enterprise very welcomed in cloud deployment scenarios. Many teams in Oracle Cloud Infrastructure have already tested and seen improved performance by running their services on GraalVM. 

If you would like to try this out but do not have an account, then sign up for the Oracle Cloud Free Tier program. If you are an Oracle Cloud user, try running a  workload with the GraalVM Enterprise environment and evaluate the cost-effectiveness.

 

Member of Technical Staff
More about Olga Gupalo

Share