AWS Lambda – Spring vs Micronaut

Prerequisites

  • AWS Account
  • installed aws-cli
  • java 8

The source code for this blog can be found in our GitHub repository.

The go-to solution for writing serverless functions with Spring is the Spring Cloud Function project. It provides a unified programming model for different cloud providers; therefore your business logic is not dependent on any cloud provider. It also decouples the business logic from a specific runtime target, so there is no difference if you test your code locally, run it as a web endpoint or for example as a stream processor. Of course, it also enables all the Spring boot features like dependency injection or auto-configuration.

Micronaut is a new framework for microservice development that promises fast startup time, low memory consumption and compile time dependency injection. It has built-in cloud support that includes, for example, support for multiple discovery services or distributed tracing tools. There is also support for functions that can easily be deployed to AWS Lambda.

As startup time is one of Micronauts main features, we will try how it will perform in comparison to Spring Cloud Function, as the startup time is crucial if you want to run your code serverless. 

We create two small sample functions, one using Spring and the other one using Micronaut. Using the Spring Initializer and the micronaut-cli, both projects can be easily bootstrapped.

The implemented functions get a String as input and simply return the reversed String as an output. They both use the same algorithm, as this should not influence the comparison.

@Bean
public Function<String, String> reverseString() {
    return stringMessage -> new StringBuilder(stringMessage).reverse().toString();
}

Spring Cloud Function – Function Bean

@FunctionBean("micronaut-function")
public class MicronautFunction implements Function<String, String> {
    @Override
    public String apply(String request) {
        return new StringBuilder(request).reverse().toString();
    }
}

Micronaut Function

To deploy both functions to AWS Lambda, there is a deployment script (lambda-deploy.sh). This script builds both projects and creates a new S3 bucket. Using the aws-cli, it uploads the artifacts to the S3 bucket and creates a Server Application Model – sam template. Using this template, the script creates an AWS CloudFormation stack that deploys the functions to AWS Lambda. 

Now that both functions are deployed, we can test them.

We will use the AWS Console to test out Lambdas as this is the easiest way to view the startup/execution time.  Using a simple test event, we can easily trigger our lambda functions.

The function worked and we received the reversed String “!dlroW olleH”.

Another way we could test our lamdas would be to use the aws-cli, in this case, you won’t get the execution time as easy.

aws lambda invoke --function-name FUNCTION_ARN --payload "\"Hello World!\"" --log-type Tail response.txt

After we are finished with our testing and we can get rid of the functions by simply using the cleanup.sh script, it deletes the created bucket and also the CloudFormation stack.

Results

Both lambdas were configured with 1024 MB memory; to further decrease cold start time, you could set this higher.

Cold start execution in milliseconds

As you can see, Micronaut has a much lower startup time than Spring, and for Spring applications, the startup time will increase for every single bean that has to be instantiated at the start. Micronaut uses compile-time dependency injection, therefore the startup time is not influenced by how many beans the application needs to create on startup. Of course, both frameworks can be tweaked to further reduce the cold start time, but in this example, we used the defaults that are provided when you generate the projects. 

Micronaut is a pretty new framework and not all cloud providers are supported by now, there are GitHub issues ready to be implemented to add support, but for now (22nd January 2019), it is missing. Spring, on the other hand, does provide a cloud provider independent programming model and offers adapters for multiple providers, for example, AWS Lambda, Azure and Apache OpenWhisk.

Conclusion

Java is still not one of the best languages to implement serverless functions. The cold start time is still too high to provide seamless service. Micronaut keeps its promise to have a fast startup time but it is still missing support for all cloud provider platforms.

Elias Dräxler, Software Engineer at viesure

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Close Menu