dependencies {
compile group: "org.springframework.boot", name: "spring-boot-starter-undertow", version: "1.4.4.RELEASE"
compile group: "org.springframework.boot", name: "spring-boot-starter-web", version: "1.4.4.RELEASE"
}
@RestController
@SpringBootApplication
public class App {
@RequestMapping("/")
String home() throws InterruptedException {
return "<h1>Hello World!</h1>";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
is 10x slower than:
dependencies {
compile group: "io.undertow", name: "undertow-core", version: "1.2.11.Final"
}
import io.undertow.Undertow;
import io.undertow.util.Headers;
public class App {
public static void main(String[] args) throws Exception {
Undertow server = Undertow.builder()
.addHttpListener(8080, "0.0.0.0")
.setHandler(exchange -> {
if (exchange.getRequestURI().equals("/")) {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html; charset=utf-8");
exchange.getResponseSender().send("<h1>Hello World</h1>");
} else {
exchange.setResponseCode(404);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html; charset=utf-8");
exchange.getResponseSender().send("<h1>404</h1>");
}
}).build();
server.start();
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
}
}
Undertow
wrk -t12 -c400 -d30s http://127.0.0.1:8080/
Running 30s test @ http://127.0.0.1:8080/
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.87ms 14.58ms 533.46ms 99.37%
Req/Sec 18.82k 4.23k 55.18k 74.07%
6654755 requests in 30.09s, 0.99GB read
Requests/sec: 221142.35
Transfer/sec: 33.74MB
Spring Boot + Undertow
wrk -t12 -c400 -d30s http://127.0.0.1:8080/
Running 30s test @ http://127.0.0.1:8080/
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 18.94ms 13.65ms 260.12ms 81.39%
Req/Sec 1.87k 625.33 4.82k 72.69%
667606 requests in 30.09s, 102.51MB read
Requests/sec: 22184.03
Transfer/sec: 3.41MB
That's not particularly surprising as your two examples are operating at entirely different levels of abstraction. Your Undertow example is using native Undertow HTTP APIs. Your Spring Boot example is using Spring MVC which is two levels of abstraction higher. Spring MVC builds on the Servlet API which, in Undertow, builds on Undertow's HTTP APIs.
Choosing a level of abstraction to code at is all about trade-offs. Using Spring MVC buys you quite a lot in terms of development convenience but does come with some cost in terms of performance. If performance is important to you above all else, then it may not be the right choice. However, while using something like Undertow's native HTTP API will buy you some extra performance, it'll cost you at development time for anything other than a very basic hello world style application like you've shown above.
But why Spring MVC can't detect that it has only one mapping and not use all the abstractions. It should use abstraction only when is needed.
Most helpful comment
That's not particularly surprising as your two examples are operating at entirely different levels of abstraction. Your Undertow example is using native Undertow HTTP APIs. Your Spring Boot example is using Spring MVC which is two levels of abstraction higher. Spring MVC builds on the Servlet API which, in Undertow, builds on Undertow's HTTP APIs.
Choosing a level of abstraction to code at is all about trade-offs. Using Spring MVC buys you quite a lot in terms of development convenience but does come with some cost in terms of performance. If performance is important to you above all else, then it may not be the right choice. However, while using something like Undertow's native HTTP API will buy you some extra performance, it'll cost you at development time for anything other than a very basic hello world style application like you've shown above.