TQ
dev.com

Blog about software development

Subscribe

Building micro-services in Java

21 Jan 2017 - by 'Maurits van der Schee'

In a quest for the ultimate micro-service technology I have ported the core of PHP-CRUD-API to Java. It is a REST API that reflects the tables in your MySQL database. You can find the code on my Github account. I have found Java to be extremely fast. At 14000 requests per second it outperforms implementations in all other languages (that I tried):

  1. Java, 14000 req/sec (source code)
  2. Go, 12000 req/sec (source code)
  3. PHP 7, 6500 req/sec (source code)
  4. C# (.net Core), 5000 req/sec (source code)
  5. Node.js, 4200 req/sec (source code)
  6. Python, 2600 req/sec (source code)

If you feel any code can be improved, please open an issue on Github!

Hello world example

As I did in other languages I will first show a little hello world example, that I found online, that performs very good (source):

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class HelloWorld extends AbstractHandler {

    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        response.setContentType("text/html; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("<h1>Hello World</h1>");
        baseRequest.setHandled(true);
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server(8000);
        server.setHandler(new HelloWorld());
        server.start();
        server.join();
    }
}

Save the above code as "HelloWorld.java" and download the dependency:

curl -o jetty-all-uber.jar http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/9.4.0.v20161208/jetty-all-9.4.0.v20161208-uber.jar

To compile the above code (create a "class" file) run:

javac -cp jetty-all-uber.jar HelloWorld.java

To run the above (compiled) code run:

java -cp .:jetty-all-uber.jar HelloWorld

Now connect to "http://localhost:8000/" to see "Hello World" and test using Apache Bench (run it twice without restarting the server):

ab -n 100000 -c 10 http://localhost:8000/

On my Intel NUC i7 it performs quite good at 22000 requests per second.

Warming up and the JIT

When you run Apache Bench you need to run it twice. The first time it does not perform that well (6000 requests per second for the first 10000 requests). After about 60000 requests the performance has maximized at more than double that amount. This is something we do not see (or not this extreme) in other languages.

This slow start is caused by the JIT (Just-In-Time) compiler that needs to compile and optimize certain execution paths. Executing code paths 10000s of times is recommended when benchmarking Java. In a real world scenario the warm-up period is (in most cases) irrelevant.

Using the best components

When converting the above "hello world" example to a REST API I had to include some libraries. Apart from MySQL (MariaDB) and Java (OpenJDK) I have chosen the following dependencies:

I use Maven and the excellent "maven-assembly-plugin" to package the API code and all above dependencies and their configuration in a single executable JAR file. This makes it very easy to deploy the code: Simply upload and replace the JAR file and restart execution.

Conclusion

Java is a great choice for building a REST API. It is a mature technology that can perform extremely well. It has a wide range of good tools, debuggers, profilers and IDEs. It was not as easy to get working as some other implementations, but none of them performed as well either.

Check out the code on Github!