Java Microservices: the right way

Christian Lusardi
Feb 20 · 4 min read

A real microservice is a very slim and light program with only one function with own database (if it’s necessary) and a very small memory footprint… It’s possible in Java?

Photo by Fabian Grohs on Unsplash

The problem

I’ve been working with Spring Framework for many years, and now with my team we’ve started to question it, Spring Boot in particular: is it the right choice to develop a microservice? No, because in our experience it’s too memory hungry.

I found that a basic Java application running atop Spring Boot would require a minimum of 1GB of RAM in order to run and that’s ok when you develop a middleware application, but in the microservices architecture this is very bad!

We noticed that Spring Boot applications deployed on CloudFoundry or OpenShift with k8s suffered an Out of Memory error and crash if they weren’t set to 1GB minimum.

We were looking for a new tool to help us to develop a real microservice with this technical specification:

  • Java compliant

The right framework

After a long research for a good framework (I’ll explain it in an other post) we have chosen Spark (please don’t confuse with Apache Spark). This is the right Spark http://sparkjava.com/

The solution

Right click → new Maven Project → add only strictly necessary dependencies. Below a small excerpt of the pom.xml

Well, now we define Docker file correctly…

We have chosen “openjdk:8-jre-alpine” because this starter image is the smaller and lightest in terms of memory and size. If you want to improve a little bit more the performance, you can choose Java 11…but at the moment, unfortunately, this does not exist: you can use, in the future, “openjdk:12-jre-alpine” when Java12 will be released. (You can see the complete list here: https://hub.docker.com/_/openjdk/).

The results

First of all, the weight: only 10MB jar!!! Fantastic! With SpringBoot we have always reached at least 30MB… Not so bad!

  • Start-up time (develop): with our MCU library (here to find information) and Spark the startup time is very minimalist. You can do the “hello-world” GET method less in 1 minute…

The benchmark

We have created 2 types of benchmark:

  • Hello World — Simple “hello world” message serialized in a JSON response

We have implemented this two benchmark types with:

  • Spring Boot with Undertow Application Server

There are the results:

Hello-World and compute tasks

As you can see all frameworks are equivalent but with the increasing contemporary users number, Spark starts to suffer. Well, the right focus point is the memory footprint and not only the throughput.

  • Spark memory footprint with this benchmark is irrelevant: 60 MB of Heap size and 35MB of average usage without any type of fine tuning.
Compute Task

With others frameworks the heap size is very big, for example with Spring Boot we have approximately 290–300 MB of heap (limited with -xmx JVM parameter)

The real usage is around 100–150MB, 4–5 times more heavy like Spark.

Conclusion

If you have to do a simple microservice the right choice is Spark, because:

  • it’s really very light

Now you can focus only on development and scalability leaving it to Docker and Kubernetes without thinking about the memory.

For example: 2 Spark containers uses 70MB memory or less and serves more requestes than 1 Spring Boot container.

Credits

I would like to stress and express my gratitude for the cooperation to all my team in particular Luca Pompei a great Team Leader and Developer.