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):
- Java, 14000 req/sec (source code)
- Go, 12000 req/sec (source code)
- PHP 7, 6500 req/sec (source code)
- C# (.net Core), 5000 req/sec (source code)
- Node.js, 4200 req/sec (source code)
- 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:
- Jetty: a high performance, fully featured and easy to embed web server.
- HikariCP: a high performance connection pooling library for JDBC.
- GSON: a JSON parse and serialization library that excels on small objects.
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.