Node Notes: The Reactor Pattern
A couple months ago I stumbled on a Quora question about performance of Node JS, and quickly I've been caught in the topic. After reading more on this, I realized how interesting is the architecture behind Node.JS, especially its asynchronous and single-thread nature.
In this post I'll cover what I've learned after studying a bit about non-blocking I/O operations and the Reactor Pattern, both concepts that shape Node JS.
On a common scenario, when an I/O request comes to a web server, it is assigned to an available thread. Let's say the request needs a file system access: the thread is blocked on that, until the job is done. Having many concurrent threads on a web server requires an high demand of memory.
Event-Driven architectures are a way to separate threads from connections. This way, threads will be used only by the connections to execute callbacks.
The Reactor Pattern is an implementation of the Event-Driven approach. It uses a single threaded event-loop that gathers events from client connections and dispatches them to handlers and callbacks, in a non-blocking way. After an event is registered with a specific callback, the execution immediately returns to the application. This way, the thread where Node JS runs never gets stuck in waiting for a request to be completed.
So, where does the client request get actually executed?
Node JS uses libuv, a well known C++ library that makes the non-blocking and asynchronous pattern we described happening within the Node environment. Libuv works side by side with the underlying OS and uses worker threads that allow different tasks to be executed in a non blocking-manner.
Take Home
On the practical side, Node JS introduces its own philosophy on the problem of web server scalability. While other web services are multi-threaded, Node focuses on reducing memory consumption by using only one application thread and leaving to the libuv library and the OS the problem of executing blocking operations like file system access and networking.