Performance Comparison — Reactive Vs. Non-Reactive Spring Boot Applications

Alexander Obregon
3 min readMay 16, 2023

--

Image Source

Introduction

As we immerse ourselves in the era of Microservices and cloud-based applications, the Spring Boot framework remains a popular choice for Java developers. Of late, the spotlight has been on Spring WebFlux, a non-blocking reactive web framework introduced as an alternative to the standard Spring MVC. The question often asked is, how does a reactive Spring Boot application compare with its non-reactive counterpart in terms of performance?

Let’s dive in and explore.

Understanding Reactive Programming

Before delving into the comparison, it’s crucial to understand what reactive programming is. In a nutshell, reactive programming is an asynchronous programming paradigm that revolves around data streams and the propagation of change. This means that it readily handles requests and events as they come, without blocking or waiting, thus potentially increasing system throughput.

Setting Up the Experiment

To compare the performance of reactive and non-reactive Spring Boot applications, we’ll create two simple RESTful services using both paradigms and subject them to load testing.

The Non-Reactive Spring Boot Application

For the non-reactive Spring Boot application, we will use Spring MVC, the traditional servlet-based stack.

@RestController
public class NonReactiveController {

@GetMapping("/nonreactive")
public ResponseEntity<String> getNonReactive() {
return new ResponseEntity<>("Hello from Non-Reactive!", HttpStatus.OK);
}
}

The Reactive Spring Boot Application

For the reactive application, we will use Spring WebFlux, which employs Project Reactor and Netty for non-blocking execution.

@RestController
public class ReactiveController {

@GetMapping("/reactive")
public Mono<ResponseEntity<String>> getReactive() {
return Mono.just(new ResponseEntity<>("Hello from Reactive!", HttpStatus.OK));
}
}

Performance Testing

For our performance testing, we will use Gatling, a powerful open-source load and performance testing tool. We’ll simulate a scenario where 1000 users send GET requests to both applications over a span of one minute.

class PerformanceSimulation extends Simulation {

val httpProtocol = http.baseUrl("http://localhost:8080")

val nonReactiveScenario = scenario("NonReactive Scenario")
.exec(http("NonReactive Request").get("/nonreactive"))

val reactiveScenario = scenario("Reactive Scenario")
.exec(http("Reactive Request").get("/reactive"))

setUp(
nonReactiveScenario.inject(atOnceUsers(1000)),
reactiveScenario.inject(atOnceUsers(1000))
).protocols(httpProtocol)
}

Analysis

Upon executing the test, you’ll likely observe a remarkable difference in performance. The reactive application typically handles the load more efficiently, reflecting fewer errors and quicker response times. This is because the non-blocking nature of reactive programming allows it to deal with requests as they come without waiting for available threads.

However, this doesn’t mean that reactive programming is always the superior choice. It shines in high-concurrency scenarios, where many requests must be handled simultaneously. In contrast, traditional Spring MVC may perform comparably or even better with low concurrency, where the overhead of creating many threads is not an issue.

Considerations

While reactive programming offers a performance boost in high-concurrency situations, it also introduces complexity in terms of programming model and debugging. Traditional blocking code is straightforward and easier to follow, while reactive code can be more challenging due to its asynchronous nature. Therefore, it’s essential to consider these trade-offs before deciding to go reactive.

Conclusion

The choice between reactive and non-reactive Spring Boot applications depends on multiple factors. Reactive applications, such as those built with Spring WebFlux, often perform better under high loads thanks to their non-blocking nature but introduce increased complexity. Conversely, non-reactive applications are easier to understand and debug, but may not maintain performance under heavy loads. Therefore, the decision should hinge on your application’s expected traffic, your team’s resources to manage complexity, and other optimization factors such as database design, query mechanisms, and caching strategies. Ultimately, technology adoption should be driven by specific needs and not merely trends. Choose wisely based on your unique situation and requirements.

  1. Spring WebFlux Documentation
  2. Project Reactor Documentation
  3. Gatling Documentation
Spring Boot icon by Icons8

--

--

Alexander Obregon
Alexander Obregon

Written by Alexander Obregon

Software Engineer, fervent coder & writer. Devoted to learning & assisting others. Connect on LinkedIn: https://www.linkedin.com/in/alexander-obregon-97849b229/

Responses (1)