Demystifying Spring WebFlux
Developing asynchronous, non-blocking and reactive applications in Java has never been easier thanks to Spring WebFlux. In this article, we will discuss what is the difference between regular Java web app frameworks(for example Spring Web MVC) and reactive based frameworks like Spring WebFlux.
Request handling in Spring MVC
First, let’s understand how input requests are handled in a typical Spring web MVC application. Whenever an input request arrives, the web server — tomcat for example — assigns a servlet thread to handle the request like below.
As we can see servlet/container/request threads get blocked waiting for the database/external service I/O to be completed(I/O doesn’t require CPU time). Typically, by default, Spring allocates around 200 container threads, though, it can be modified at run time. In a simple to moderate loaded applications this model of handling requests works well but when number of concurrent requests go up then quickly performance starts degrading. This is because most of the time threads are blocked waiting for I/O. Of course, container thread pool size can be adjusted but threads are resource-intensive and we can’t increase them forever.
How do we solve the above problem? Probably we can use Spring Async support to offload request processing to a different thread pool but this still has the same original problems: reading/writing to container threads must be done in a blocking way(InputStream and OutputStream are blocking APIs) and many threads are needed to achieve concurrency. Basically, Spring Async just creates an async boundary between container threads and request processing threads and in the end data needs to be dispatched back to request threads in a blocking way. One way to solve these issues is to use non-blocking I/O so scaling can be done with just a few number of threads: Spring WebFlux
Request processing in WebFlux
One of the main goals for Spring WebFlux is to provide a scalable web-stack to handle concurrency with less number of threads. Webflux achieves this with what is called as event loop(if you are familiar with Node.js, it is exactly the same concept). Basically, the idea is, instead of waiting for the I/O operations to be completed, framework asks the database driver/external API client to issue a callback when the data is available. This way container threads need not go into a waiting state and could accept more incoming requests.
As seen from the diagram above, a small number of threads are sufficient (typically one per CPU) to handle a large number of input requests. Whenever an input request comes, container threads perform any pre-processing logic and creates an event with callback logic instead of waiting for I/O. Once the data is available, another event is created and one of the available container threads executes the callback logic. Here the main thing to observe is that the thread which creates an I/O event and the thread which executes callback logic could potentially be different. This approach of handling requests has two main advantages: 1) More efficient use of CPU thanks to less number of threads 2) More concurrent requests — thanks to non-blocking I/O. Sounds exciting?
However, despite these advantages, WebFlux may not be the right fit for all use cases though. Especially, if our service has any blocking things in the request flow(JDBC, JPA etc.), then we may not see the full benefits of this framework(Spring team is working on reactive and non-blocking JDBC drivers though). Also if service is not expected to receive a lot of traffic then Spring web MVC may suffice: mainly because it’s been there for quite some time(with a lot of supporting libraries) and the programming logic is easy to reason about(reactive logic could be confusing at times).
In conclusion, Spring WebFlux is an excellent reactive framework for developing Java based web services/applications. Lately, SpringBoot has started supporting Kotlin(another JVM based language) language as well so we are not limited to Java indeed. Have you used to WebFux in your service development? How is your experience? Please let me know in the comments.