Microservices in Java — A Second Look
So recently I published an article titled “Microservices in Java? Never.” And it seriously split the camps. Java developers who were passionate about the language, the tools, the frameworks etc posed some very good counterpoints and having read these points I thought I would take a second look at the language and it’s suitableness for a microservice based future.
The Flaw In My First Argument
When presenting my initial argument I don’t believe I made it clear enough about where my initial memory requirements came from. To be honest, I was indeed comparing apples to oranges as one person stated.
I stated that a basic Java application running atop Spring Boot would require a minimum of 1GB of RAM in order to run. We faced issues with Spring boot applications atop of CloudFoundry in which they would hit an Out of Memory error and crash if they weren’t set to 1GB minimum. As such, if you were to decompose a monolithic application into a series of microservices, each instance of said microservice would require at minimum 1GB of RAM. You can get away with starting the application with 512MB but you’d occasionally find your app crashing under weird conditions.
Some of the feedback I received for the last article stated you could use the memory calculator in order to specify things like heap space size but in all fairness the likelihood of a developer team doing this in a normal environment is minimal.
I used this as the basis of my argument and whilst this is true for one such environment it was slightly unfair to tarnish all Java applications under the same brush.
Digging Deeper
Let’s take a look at 3 different languages; Java of course, Python and Go. To make this more of a fair comparison we’ll write 3 barebones http servers that will just return “Hello World” when the root path is hit.
We’ll also be running these 3 distinct applications using Docker. For posterity I’ll be including the source files used to build and run these docker based containers. These will be as minimal as my limited knowledge of Docker allows.
The Go Example
The Dockerfile for our go server looks something like this.
Our go server will utilize the "net/http"
package will look something like so:
The Java Example
Our Java example, shall use a very simple httpserver using the sun library in order to run it.
We’ll be using Java 8 to serve as our base image for our java sample
The Python Example
Our Python library shall be a basic flask based application.
And we’ll be using Python 2.7 as the base for our docker container.
The Baseline Results
Upon running these 3 different containers, I was most surprised by the Python result. Python consumed more base memory than both the Java and the Go based equivalents combined.
The Go based equivalent unsurprisingly only takes up just over 1MB. The Java version just over 10MB and the Python 2.7 Docker image takes 15MB.
Digging Deeper
So based off these somewhat weird results I decided to dig a bit deeper and see how much the likes of a Spring Boot application would consume and how much a Python 3 aiohttp/asyncio based server would consume. To my surprise, I found that the Python 3 version aiohttp was heavier still and came in at around 18MB to run a simple server.
The Spring Boot Giant
Now it was time time to put Spring Boot docker container to the test. I put together a hello-world style Spring Boot application and compiled it using maven. I started it up and saw that it was using over 260 times the memory it than that of the go based equivalent.
The Dockerfile for our sample app looks something like this:
Whilst the grand sum of our project’s dependencies takes this form:
As you can see nothing other than a json library, and our spring boot dependencies are pulled into this.
After building the docker image and firing her up we then got results that looked like this:
Conclusion
Comparatively speaking, using something like Spring Boot as the base of all your microservices could see you face much the same fate as was outlined in my previous article. You’ll pay significantly more in regards to infrastructure costs and you’ll ultimately be paying for features that are simply not needed in most projects.
Using Spring Boot for every project is like buying a high powered gaming PC when all you really needed was a Raspberry Pi. By choosing a smaller framework and considering your options before you Spring Boot all the things! you could be saving yourself a shed tonne of money.