Full Reactive Stack: Conclusions

Full Reactive Stack: Conclusions

In this final section, we run the application and see how everything works for the two different approaches: WebFlux with Server-Sent Events and MVC blocking classic. This post compares those two alternatives as well, in terms of user’s experience, performance and ease of development.

> Full Reactive Stack with Spring Boot and Angular
GitHub
This guide focuses on the capabilities of Spring WebFlux and Spring Boot 2 to create a Reactive Web Application, supported by a code example that you can build step by step.
Part 4. Conclusions (this article)
Table of Contents

This post is a blog version of one of the parts of the Full Reactive Stack with Spring Boot, WebFlux, Angular, RxJS and Eventsource Guide. The complete code sources are on GitHub.

Get the complete guide now on Leanpub

WebFlux vs. Blocking (MVC): user experience

Let’s start our comparison with the most noticeable difference for Web Users: user experience. We’ll use the frontend for this comparison.

Playing the user’s role is quite simple in this application: enter values for the given parameters (pagination, page number, and size) and press either the ‘Reactive Request’ or the ‘Blocking Request’ button. That will put our implementation into practice, calling the backend services from the web page and processing the response either as small portions (WebFlux) or as a whole thing (Web MVC). This is covered by the previous chapters, so we won’t dive into details about how this works.

You’ll find out quickly that, for the non-paginated requests and big page sizes, the user’s experience for the reactive case is much better. You don’t need to wait for the request to finish to start reading the quotes. Besides, keep in mind that this is a simulated scenario in which we’re forcing a constant delay per element from the server. In a real situation, where the server’s response time and the network latency may vary unpredictably, the benefit would be even more noticeable.

Angular Reactive App - Quotes

As mentioned in the first chapter, it’s a known fact that web users abandon slow sites. Following the same example we used back then, it’s much better to show a few products of your online store as soon as possible to your potential customers than keeping them waiting for all the content to appear at once.

WebFlux vs. Blocking (MVC): performance

Interestingly enough, implementing a Full Reactive Web Stack introduces some extra delay in the total time required to retrieve a response from the server. That’s due to the extra processing needed to make the communication work. Therefore, we can’t extract conclusions by looking at the requests one by one.

The Reactive Web approach shines when we measure the whole performance of the server when handling multiple requests at the same time. In this section, we’ll go through different test configuration options and we’ll see the results in graphs that compare the WebFlux implementation with the Web MVC one.

The results come from a benchmark test that you can run yourself. In the GitHub backend’s project folder, spring-boot-reactive-web, you’ll find the test class BenchmarkTest. Remove the @Ignore annotation and run the tests or just use your IDE to execute it.

Benchmark details

I used an Intel Core i7 @ 2,5 GHz with 1 processor and 4 cores for the test. The backend runs from IntelliJ IDEA (not Docker). I didn’t modify the default configuration for Netty, which in my case is running 8 parallel server threads.

The benchmark allows you to configure:

  • The total number of requests to execute.
  • The number of requests to run in parallel (parallelism).

Every request performed by the client should take at least one second since the delay per element is 100ms and we’re asking the server for 10 quotes. The existing code runs 1, 8, 32, 96 and 768 requests four times:

  • With parallelism of 32 and invoking the reactive endpoint.
  • With parallelism of 32 and invoking the blocking endpoint.
  • With parallelism of 96 and invoking the reactive endpoint.
  • With parallelism of 96 and invoking the blocking endpoint.

To avoid potential differences in the test implementation, both reactive and not reactive requests use a WebClient, the reactive client that comes with the new Spring WebFlux. I also tried with RestTemplate for the blocking part with very similar results. The log levels of the application are in the repository so you can get some valuable information from them when running the Benchmark: threads started, locks acquired and released, etc.

Server’s Side: Requests Served per Second

As you can see in the graph below, WebFlux scores much better for a high load. It’s capable of processing almost all the requests in parallel, reaching 30 requests/second when we execute 32 requests at once and 90 requests/second for 96 simultaneous calls.

Server requests per second - MVC vs. WebFlux (32)
Server requests per second - MVC vs. WebFlux (96)

When we execute blocking calls, the server can’t process so many requests in parallel. It’s clearly limited by the number of server threads running, eight in this case.

This proves that a Reactive Web approach optimizes the server resources by unblocking the server’s threads and processing the requests separately, in parallel.

Client’s Side: Average Time per Request

This metric also shows WebFlux as the winner option. The Netty server keeps all the reactive requests close to the minimum of one second, which is actually the consequence of the server being able to cope with almost every request in parallel.

On the blocking landscape, the higher the number of parallel requests the longer the request takes to complete in average. It makes sense: given that all the server threads are busy, the remaining requests need to wait, thus increasing the average time. On the functional side, many users would be unhappy because the web page takes a long time to load.

Average time per request - WebFlux vs MVC (32)
Average time per request - WebFlux vs MVC (96)

Bear in mind that this benchmark shows a clear winner because it focuses on a key server resource: the number of parallel threads available. We could make the classic Web stack perform much better:

  1. A first option would be to increase the number of parallel threads available in the server, adjusting them to our needs.
  2. On the implementation side, we could switch to asynchronous processing at the controller layer. This could be achieved for example by returning a DeferredResult or a Callable as a response. See the Asynchronous Requests section in the Spring docs for more information.

WebFlux vs. Blocking (MVC): ease of development

This is the most subjective angle that we can use to compare both approaches. However, I think it’s very important because it would be risky to blindly choose WebFlux because of the value it brings to user’s experience without considering other factors.

For instance, take into account the knowledge of Reactive Patterns in your organization. It’s clearly a change of paradigm and there are many ways in which things can go wrong if people are not properly trained in these concepts. You might end up with an amazingly-performing web server which is a nightmare to maintain from the developer’s point of view.

In my opinion, the readability of code may get worse with reactive patterns. Large chains of methods with a weird indentation where the reader struggles to figure out the logic behind unless there is good inline documentation or a very good code assistance from the IDE. On top of that, there is also extra complexity associated to debug these code blocks that do not return values immediately.

Suitability

You should evaluate if a Full Reactive stack fits your case. Do you require SQL queries to complete your Web response? Bad news: reactive support for relational databases are still at a very early stage.

Look also at the client’s side: can your web clients switch to a reactive approach? If the answer is no, then the list of advantages you’ll get becomes smaller.

Testing

Writing Unit and Integration tests for reactive streams with WebFlux might be tricky. The Project Reactor documentation is a good starting point, showing how you can use for example StepVerifier to check that your Fluxes and Monos work the way you want.

You can also find examples of Unit Tests in our backend application’s GitHub repository.

An extra inconvenience is that there isn’t a big community of developers from where you can see examples of testing with WebFlux yet. Besides, the tests are not as readable as the MVC ones, and they are also harder to debug if something goes wrong.

Conclusions

Like any other technology choice, WebFlux (and the Reactive Web approach in general) has advantages and downsides. Don’t go for it just because it’s the new thing to do.

As we saw in this guide, WebFlux can bring performance benefits and can also leverage the experience you provide to your users when they’re waiting for the response’s data. On the other hand, reactive programming comes with new ways of writing, testing, and debugging code, so it’s not a quick transition.

I always recommend a very good analysis of not only the requirements of your application but also other aspects of your organization. Is the development team ready for the change? Can you solve all the challenges you’ll face? Will you really use the benefits or are they just nice-to-haves?

For an existing project that may take advantage of it, I’d rather try it in a limited scope. You could implement this approach in a separate component (or module, or microservice). Evaluate the results; then, you can refactor the rest of the code if you see that it brings value.

I hope you enjoyed this guide. Feel free to give me some feedback via Twitter, GitHub, or any other channel you prefer.

Would you like to know more about Spring Boot applied to a Microservices Architecture? Learn all these concepts from a practical perspective with my new book.

Did you like this post? Get the complete Full Reactive series in a book format on Leanpub.

This article is part of a guide:
> Full Reactive Stack with Spring Boot and Angular
GitHub
This guide focuses on the capabilities of Spring WebFlux and Spring Boot 2 to create a Reactive Web Application, supported by a code example that you can build step by step.
Part 4. Conclusions (this article)
Moisés Macero's Picture

About Moisés Macero

Software Developer, Architect, and Author.
Are you interested in my workshops?

Amsterdam, The Netherlands https://thepracticaldeveloper.com

Comments