Today our Hunters tell us about Spring WebFlux, the MVC framework that is part of the new Spring Framework 5.x release for applications developed under a reactive paradigm.
Reactive applications are non-blocking applications, whose threads handling requests never wait for input/output operations to be resolved: calling an external service, querying a database, accessing a file in the system... Instead, the request is sent, a callback function is registered to be executed when the requested resource is available, and then the thread moves on to another operation. This minimises waits, but also optimises CPU and memory resources, as fewer threads are needed to handle requests. This is why a reactive application scales better than an imperative one.
What is the architecture of Spring WebFlux?
Imperative MVC applications work under Servlet specification up to version 3.0 and are based on a thread pool model where each request is sent by a thread created for this purpose.
Each thread sending the request is blocked while it resolves input/output operations, such as querying a database. Also, any information that the thread may need (security context, database transaction status...) is stored in the ThreadLocal structure.
Figure 1: Servlet Dispatcher.
Classic MVC architecture uses a thread-per-request model:
Figure 2: Thread-Per-Request.
In this case, a thread will send the request and if there is any blocking, such as a database request or access to a remote file system, it will wait until the resource becomes available.
Applications developed under Spring WebFlux follow a functional reactive paradigm. Reactive programming is a functional declarative paradigm that relies on asynchronous data flows and change propagation.
As requests are handled by several threads, Spring WebFlux does not use ThreadLocal, which would be pointless and very expensive. Instead of ThreadLocal, it uses a feature called Context.
For request handling, ServletDispatcher is replaced by DispatcherHandle. Servlet filters are replaced by WebFilters.
Additionally, Spring WebFlux uses Project Reactor (also supporting RxJava) as a reactive engine. Reactor requires Java 8 to run.
Figure 3: Servlet Dispatcher.
The threading model used by Spring WebFlux is called event loop. This is how it works:
Figure 4: Event Loop.
In this model, there is one event loop for each logical core of the CPU. The idea is that each request becomes an event, which is processed sequentially. Processing consists of registering a callback and returning immediately. When the input/output operation is completed, the callback is executed and the response is thrown back to the original caller. This model is implemented on servers such as Netty, Node.js or Nginx.
MVC vs WebFlux
WebFlux-based systems scale much better and respect response times by handling the workload better. To demonstrate this, we carried out a simple test:
Two versions of the Rest service were created, retrieving 1300 records from an H2 in-memory database without any filtering or sorting. The test parameters were:
- A CPU with 8 logical cores and 2.42 GHz frequency.
- 32 GB RAM at 3200 MHz.
- 500 concurrent users attacking the Rest services to get all records (findAll).
- 0 iterations. In total, 5000 requests handled.
Figura 5: Imperative vs Reactive.
We obtained the following metrics:
- Memory peaks of 415 Mb.
- More than 100 threads created.
- CPU peaks exceeding 50% capacity.
- 13,065 classes loaded.
- Memory peaks of 310 Mb.
- Less than 40 threads created.
- CPU peaks below 15% capacity.
- 10,847 classes loaded.
These metrics allow reactive systems to handle more load than imperative systems.
Main findings from the use of Spring WebFlux
- Spring WebFlux has better performance parameters, provided that the I/O data has some latency.
- Reactive programming involves a significant learning curve, as it involves a paradigm shift.
- Spring WebFlux and Spring MVC can be used together, but WebFlux loses a lot of capability, so it’s better to go for a 100% reactive approach.
Since WebFlux requires non-blocking Input/Output operations, there is still a lot of work to be done, as not all relational database drivers are adapted to this paradigm.
WebFlux also breaks with the classic Servlet specification (supporting Servlet 3.1+), so modules such as Spring Security are affected and different configurations are required depending on whether an imperative or reactive approach is used.
In a nutshell: WebFlux is a good bet for the implementation of resilient, elastic and fault-tolerant systems but it requires a bit of a fresh start when it comes to the tech, because although it is still Java and Spring, the way of doing things has changed.
Want to know more about Hunters?
At Altia, we have designed several programmes for people who are finishing their degrees and recent graduates to start out in the IT sector, bringing their talent and passion for technology. One of these programmes is Hunters: trailblazers who love to follow trends and want to help anticipate future challenges.
Being a Hunter means being part of a diverse group that generates and transfers knowledge.