Spring Boot performance battle: blocking vs non-blocking vs reactive

CPU was low, memory was good, but we were able to handle only 200 requests/sec.

This was Servlet thread per connection issue. The default thread pool is 200 that was why we have 200 requests/sec for 1000ms response time.

  1. Increase the thread pool size
  2. DeferredResult or CompletableFuture with Servlet
  3. Spring reactive with WebFlux

Let’s test this stuff

Test environment:

@GetMapping(value = "/sync")
public String getUserSync(@RequestParam long delay) {
return sendRequestWithJavaHttpClient(delay).thenApply(x -> "sync: " + x).join();
}
@GetMapping(value = "/completable-future-java-client")
public CompletableFuture<String> getUserUsingWithCFAndJavaClient(@RequestParam long delay) {
return sendRequestWithJavaHttpClient(delay).thenApply(x -> "completable-future-java-client: " + x);
}
@GetMapping(value = "/completable-future-apache-client")
public CompletableFuture<String> getUserUsingWithCFAndApacheCLient(@RequestParam long delay) {
return sendRequestWithApacheHttpClient(delay).thenApply(x -> "completable-future-apache-client: " + x);
}
@GetMapping(value = "/webflux-java-http-client")
public Mono<String> getUserUsingWebfluxJavaHttpClient(@RequestParam long delay) {
CompletableFuture<String> stringCompletableFuture = sendRequestWithJavaHttpClient(delay).thenApply(x -> "webflux-java-http-client: " + x);
return Mono.fromFuture(stringCompletableFuture);
}
@GetMapping(value = "/webflux-webclient")
public Mono<String> getUserUsingWebfluxWebclient(@RequestParam long delay) {
return webClient.get().uri("/user/?delay={delay}", delay).retrieve().bodyToMono(String.class).map(x -> "webflux-webclient: " + x);
}
@GetMapping(value = "/webflux-apache-client")
public Mono<String> apache(@RequestParam long delay) {
return Mono.fromCompletionStage(sendRequestWithApacheHttpClient(delay).thenApply(x -> "webflux-apache-client: " + x));
}

Load numbers

For performance test, we will use Jmeter. We will test our service for 100, 200, 400, 800 concurrent requests for 10,100,500 ms delay. Total 12 tests for each implementation.

Build artifact

Test code you can see on my GitHub https://github.com/Aleksandr-Filichkin/spring-mvc-vs-webflux

mvn clean install -P web-flux
mvn clean install -P servlet

Throughput results(msg/sec)

Throughput

CPU Utilization

CPU utilization

Test 10 ms delay for underlying service (100,200,400,800 concurrent users )

Test 10 ms delay for underlying service (100,200,400,800 concurrent users )

Test 500 ms delay for underlying service ( 100,200,400,800 concurrent users)

1)Blocking with Servlet

Scaling policy problem:

The biggest problem for REST/microservice is scaling policy.

Conclusion (on a single core, 1GB RAM server instance):

Blocking with Servlet performs well only for the case when underlying service is fast(10ms)

Next Performance battle

If you like it, please read my new post:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store