Serverless Native Java Functions using GraalVM and Fn Project

郭弘盛
2023-12-01

TL;DR;
Java Functions compiled into a native executable using GraalVM reduces cold start times and memory footprint by order of magnitude compared to running on JVM.
Native Java Functions performs equal to or better than Go functions in terms of execution time and memory used.
Native Java Functions executable runs from scratch base image, thus have a similar size compared to Go executable images.
Source code is available at https://github.com/panga/fn-native-java

panga/fn-native-java

fn-native-java - Fn Project Native Java Function using GraalVM
github.com
What’s GraalVM?
GraalVM is a High-performance polyglot VM open sourced by Oracle and currently in active development.

It also has the ability to compile JVM languages and a few other languages like JS, Python, Ruby and R into native executable. Some examples are demonstrated in @graalvm blog.

The executable actually runs in a optimized native VM called “SubstrateVM”. Although is quite stable nowadays, it still contains some limitations that are currently being worked on and can be released in near future.

What’s Fn Project?
The Fn Project is an open-source container-native serverless platform that you can run anywhere — any cloud or on-premise. It’s easy to use, supports every programming language, and is extensible and performant.

It is an evolution of the IronFunctions project from iron.io and is mainly maintained by Oracle. So you can expect enterprise grade solution, like first class support for building and testing.

It basically leverages of the container technology to run and you can get started very quickly, the only prerequisite is Docker installed.

First, you need to install and start Fn Server using the following commands:

curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
fn start
The Fn introduction tutorial explains how to run your first function, while the Java introduction tutorial shows the Java function example.

Creating a Native Java Function using GraalVM
What’s a Native Java Function?
I will call any Java code that is compiled Ahead-of-Time (AOT) into a native executable that does not require a JVM to run as Native Java Function.

What problem does it solve?
Java is often blamed as being heavy and not suitable for running as serverless function.

That fame does not come from nothing, it sometimes needs a full JRE to run with slow startup time and high memory consumption compared to other native executables like Go.

Fortunately this isn’t true anymore, with new versions of Java you can create modular applications, compile Ahead-of-Time and have new and improved garbage collectors using both OpenJDK and OpenJ9 implementations.

GraalVM is new flavor that delivers a JVM that supports multiple languages and compilation into native executable or shared library.

Steps to create your first Native Java Function using GraalVM
Create a new Java function with fn init --runtime java8 myfunction
Create reflection.json for enabling reflection in the function entrypoint

  1. Create Dockerfile using GraalVM CE base image provided my me

  2. Change func.yaml to use docker runtime and add build commands:

  3. Build and deploy the function

fn deploy --app myapp --local
6. Call the function

curl -d ‘Leonardo’ http://localhost:8080/r/myapp/myfunction
Note: More advanced use cases using fnproject/fdk-java are also working.

Benchmarking
All the benchmarks are done using my local machine (MBP 2015) with default function templates created using Fn Cli.

The executions were done using the following command:

curl -d ‘Leonardo’ http://localhost:8080/r/myapp/myfunction
Cold Execution Times
Java Function -> 660 ms
Native Java Function -> 460 ms
Go Function -> 470 ms
Note: Most of the time consumed in cold execution of Native Java Function and Go Function was the container startup, the real execution time is near 0 ms.

Hot Execution Times
Java Function -> 30 ms
Native Java Function -> 30 ms
Go Function -> 30 ms
Container Memory usage of Hot Function
Java Function -> 17.8 MiB
Native Java Function -> 0.9 MiB
Go Function -> 1.2 MiB
Container Image Size
Java Function -> 266 MB
Native Java Function -> 13.6 MB
Go Function -> 15.1 MB
Conclusion
It is a good time to start trying Java Functions on Serverless solutions!

Update on 2018–06–24
Changed Dockerfile from alpine base image to scratch in order to demonstrate the independence of generated native executable.

Thanks Codrut Stancu!

 类似资料:

相关阅读

相关文章

相关问答