Should We Use A Reactive-stack Web Framework Like Spring Webflux When We Have Blocking Calls?

- 1 answer

I'm trying to understand when we would use a reactive-stack framework like webflux. I've read articles that seems to suggest that we would benefit from reactive approach when we have many blocking calls. For example, if we had a webhook service that needs to call client servers to update them with information.

But I also read here

A simple way to evaluate an application is to check its dependencies. If you have blocking persistence APIs (JPA, JDBC) or networking APIs to use, Spring MVC is the best choice for common architectures at least. It is technically feasible with both Reactor and RxJava to perform blocking calls on a separate thread but you would not be making the most of a non-blocking web stack.

And this seems to suggest the exact opposite. I read that reactive is more useful if you can stream the information. Example if you have a frontend asking for a list and a reactive source that can give you the information as it becomes available rather than only all of it when it is done.

So the question is when should we use reactive for backend? Should we use it when we have many blocking calls? E.g. HTTP calls to a client where we need to wait for the responses. Or is that exactly the wrong use case for it?

I'm aware there are other considerations like the complexity of the code. I know the reactive approach is harder to implement but I'm only asking about performance and scalability here.



its very hard to give you any concrete answer here since we dont know your exact architecture.

But if you understand the problem reactive is trying to solve, and how it does it might give you a better insight into making a better decision.

The traditional servlet approach that most web servers in java uses assigns one thread to each request. So as a request comes in, one thread is assigned to it, and this thread then processes the request. If your server then does blocking calls to other servers, the assigned thread needs to wait for the response to come back.

This tends to result in that web servers have several 100s of threads that spend a lot of their time just waiting. And when i mean waiting, i mean waiting a lot. As much of 90% of the time of a thread could be spent just waiting for a blocking call. For instance the processing in a web server might take 3ms, then it does a blocking database call, and the thread needs to wait 200ms (don't quote me on the numbers).

That is a lot of resources spent just waiting.

So old way:

  • one thread per request
  • if 300 request then we have 300 threads
  • High memory usage (each thread needs memory)
  • CPU spends a lot of time waiting

Reactive solves this by having something called an event loop, and then a small thread pool that schedules work on the event loop.

I practice you can se it like this, one event loop, and then maybe 10 threads that all schedule work, the event loop just works, all the time, and the schedulers jast schedule a long line of work for the event loop to push through. So all the threads are constantly 100% busy.

But this means that we need to be 100% non-blocking. Imagen we have a blocking call in this scenario, then the entire eventloop would stop, all the scheduled jobs would stop, and the entire machine would freeze until we are "un-blocked".

So reactive:

  • event-loop does all the work
  • small thread pool that schedules work
  • blocking is VERY bad, can freeze entire application
  • since less threads, smaller memory footprint
  • higher CPU usage
  • Possibly higher throughput

So we are basically trading memory for CPU power.

So what is a blocking call? well most calls are blocking as in you call another service and you need to wait. But this is where reactive shines.

Since it does not have one specific thread per request, any thread can make the request, and any thread can handle the response as it comes back. So we are what is called thread-agnostic. Or non-blocking service can still do a lot of blocking calls to other services and still stav completely non-blocking. Cause when say non-blocking im meaning non-blocking internally inside our own application.

But what is a bad blocking call? well its when you are calling something that is thread dependent. Which means that you are calling something that needs to have the same thread that made the call to handle the response. because then that thread needs to block.

It has to make a call, block, then handle the response. And this is bad, very bad.

So for instance everything that uses ThreadLocal is bad, and this is where one of the major problems come in. JDBC (the database driver specification) was written inherently blocking. As it is dependent on thread local to keep track of transactions to be able to rollback. Which means that all database calls using JDBC are inherently blocking, which means you have to use database drivers that uses the R2DBC spec.

But a rest call isn't blocking, as it is not thread dependent unless you use thread dependent functionality, like ThreadLocal etc.

What is mentioned in your quote is that spring reactor has a mechanism so that you can mix the "old way" with the new way. This means that if you would have a blocking call, you can explicitly tell the framework that "all calls to this (for instance) this database should be placed on its own thread pool" so you are sort of telling the framework that use the old way (by assigning one exclusive thread for that request) when you are calling a specific service, or database, but remember then you loose all the reactive benefits.

If your service is only calling a lot of hard blocking services, you would have to constantly opt out of the reactive framework, so you would basically just build an old web service using a reactive framework, which is sort of an anti-pattern.

All i have written here is general computer knowledge, how threads work, how rest calls work, how database drivers work. I can't explain how computers work in a single stack overflow post.

This and a lot more is stated in the Reactor reference and i suggest you do more research.

If you have a road with many turns and no straights, is there any purpose to buying a F1 car if you constantly have to slow down and do a lot of turns all the time?

I leave that decision to you.