Apparently I’ve been living under a rock, and just crawled out of it, but reactive is all the rage right now. Maybe I am showing my age, but reactive seems like cooperative multitasking.
So, my question is… Why do it and why all the fuss around it?
Let me give you a bit of background…
I have tried to build a complex high-performance reactive system about 10 years ago. It seems like a long time ago, but the reality is that Linux kernel has not changed all that much in that time, nor the environment in which user-space programs run under Linux, so the takeaway from my experience then fully applies to the systems environment today.
Let’s list the supposed advantages of a reactive system:
What are reactive’s disadvantages?
Let’s compare what both user-level and kernel-level steps that are required for a synchronous, blocking, multi-threaded system vs. non-blocking reactive system.
The task here is to do one cycle either through event loop in case of a reactive system, or perform one read/write in a synchronous blocking system, which accomplishes the same thing.
Blocking / Thread-Pool:
Reactive / Non-Blocking / Single-threaded:
As you can see, the steps involved in reactive architecture are more involved, and there are a lot, really a LOT more steps involved to do the same task. Also, in case of a blocking system, all the tasks are exactly the ones the kernel is does very well, and kernel is optimized to perform exactly those tasks. This can’t be said for a reactive system, as the tasks are done that are not optimized to be done this way.
Reactive architecture executes much more slowly, using much more CPU resources for the same task, and the benchmarks support this. There are also latency issues since there is a single thread dealing with multiple connections, latency is naturally increased.
The benchmarks used are basically a load test.
Of course, real life is not like a load test. There are HTTP 1.1, WebSocket, and other scenarios that require many idle connections. This is where reactive has it’s only advantage.
Let’s talk about this and other advantages that reactive has:
Idle connections, and only idle connections can be handled effectively in a reactive way. Web server knows when a connection is likely to be idle, i.e. after an HTTP request is done in HTTP 1.1, and server can put that connection in a pool that’s handled by a poll() loop in a separate thread. The connection is never marked non-blocking.
This way, when a connection stops being idle, it can be put back in a thread pool which will process it in a regular, blocking way.
Another false advantage of reactive is lower memory footprint. This can also be mitigated by setting thread stack size low for the connection processing thread pool.
Conclusions: