Logo courtesy: http://reactivex.io/
There is a lot of hype around this shiny new thing in web applications development world called being “Reactive”! There are many frameworks popping up with this slogan, e.g., Vert.x, Akka, Spring Webflux, Play, RxJava, RxJS etc. to name a few. What does it mean? and why is this hype? is it worth your time? Let’s explore…
What does Reactive mean exactly?
Being reactive means ability to “react” to “events/changes”. One very simple example is how a column in excel-sheet gets updated (reacts) if the column which it depends upon changes.
This is a known design pattern and can be implemented using “Observer pattern” or a “Publisher-Subscriber pattern”, where there is a publisher and one or more subscribers to it.
There are two distinct things which are Reactive, [a] Reactive programming, which uses the reactive programming principles (including the above stated observer pattern) and [b] Reactive system where an entire system follows the guidelines of the “reactive manifesto”. The latter one in fact is much bigger picture.
There is a really cool post about this difference from Lightbend, do check it out! We will however stick to the “reactive-programming” for the scope of this article.
We just saw that we can implement reactive using our plain-old Observer pattern or a Publisher-Subscriber (PubSub) pattern.
So, is this it?
Try to fit every piece of your code with a Pub-Sub pattern, you would need certain disciplinary guidelines to be able to make use of it without pulling your hairs out! In fact there are more than just PubSub and Observer pattern to implement reactive e.g., event-loop, actor model etc.
There are some fundamental building block of the reactive programming model:
Non-blocking: Execution of a task shouldn’t block another task’s execution.
In our PuSub context, any event should be handled without blocking the execution of upcoming events.
Asynchronous: Tasks happen asynchronously/separately and may notify after they’re done. Most popular programming pattern seen with this model is callbacks.
CompletableFuture is a very good example for asynchronous programming in Java:
The above code is asynchronous as well as it won’t block! Most often than not, non-blocking and asynchronous are the same thing. If a piece of code is asynchronous, it has to be non-blocking and vice-versa.
There is one major problem with the callbacks, and that is the Callback Hell when we have more than 2 nested callbacks, the code starts to look obscure and becomes unmaintainable very quickly.
Functional/Declarative: To overcome the callback hell and be able to compose (or chain) the operations on the events subscribed, we should use the functional/declarative style. Suppose there is a high level construct of Publisher and Subscriber such that we could use:
The above code looks more elegant even though it performs a lot of things in steps with a merge chaining of functions. It was just an example taken from Spring Webflux’s Publisher/Subscriber API. There are other reactive libraries and frameworks where this type of functional composition and chaining is possible.
Java 9 also has introduced Reactive Streams and it would be exciting to see how this evolves over time.
OK, what to I get from being Reactive?
In a traditional blocking code, a thread may get blocked and awaits for the result of some other task. While waiting, it is simply doing nothing! But since, the thread is there, it will consume the precious CPU cycles, waking up checking if the execution is completed and going back to sleep if the result has not arrived.
While, non-blocking code usually implemented using either,
Event-loop: I is essentially just a single thread! This event-loop executes/notifies the process to be run/invoked next without getting blocked. Hence, instead of multiple threads waiting for the resource, there’s just this one thread which handles all the I/O and resource allocation to different requests. Just like a waiter does for multiple customers. Example implementations are Vert.x, nodejs, etc.
Event driven thread-pool backed mechanism: Event driven mechanism involving very small number of threads usually employs some virtual process units (actors, verticles, queue etc.) on top of a thread-pool framework (Fork-Join) making an efficient use of it. Example implementations are Akka Actor model, Reactor, etc.
In addition to that, subscribers being notified (push based) on events by the publisher means that subscribers don’t have to keep polling for the events, saving further more CPU resources.
Ultimately this all leads to better resource management and this is why the reactive model can work with even lesser number threads.
Why the sudden Need?
We live in the era of “clouds” and “scale”. And by scale, I mean massive scale with thousands to hundreds of thousands users concurrently using your application.
Before the “reactive” hype, every web application out there used to work on a synchronous/blocking “1 thread per request model”. Which means that a thread is allocated for every request! This model served perfectly well for us in past, but in today’s age of mobile apps cheaper and accessible internet, the number of users a “viral” app has to handle can grow really fast.
This massive scale demands resources (larger or more machines) and getting resources in cloud costs money! So, we desperately needed a model which could scale even with lesser resources. In our case lesser number of threads for a highly concurrent application.
As we discussed about this reactive model of programming, you might have had the impression of this being the holy grail for modern web programming. This does in fact also add some noticeable complexity to the system. As they say,
If you consider all you have is as a hammer, everything else will start looking like a nail!
There is a lot, which is required from a developer to develop truly reactive applications:
Discipline is Needed: If you are using a reactive framework and the database driver is blocking, you will end up blocking threads, same applies to every other block of you system. Hence, to have a proper reactive application, you have no option but to go “all reactive”!
This adds even more complexity and does influence many critical design decisions that have to be made, such as:
- Which DB to use, does it have reactive drivers?
- Does the libraries I am using support reactive?
- Is there any blocking operation that I am doing within my system?
- Do I have written appropriate adapter/wrappers over all the non-reactive components?
So, better stick to the traditional frameworks unless there is a need otherwise. Some such scenarios could be:
- Highly concurrent application.
- With limited resources.
- Handling request spikes (back-pressure).
This is all from me and hope you got some reactive knowledge out of this post.
Thanks for Reading and have a Good day :)