Understanding the Node Architecture
This blog thoroughly explains the Node Architecture, from the client-side to the server. Firstly, let us understand why Node Architecture is so popular and what makes Node Architecture best-of-class.
What is NodeJS?
Diagrammatic Explanation of a Browser Architecture
The following is the description as per the Official Node Page:
Before we get into the depths of how Node Architecture works, let us understand what comprises this architecture. Broadly, Node's architecture consists of six main components.
- Requests: The most fundamental component, which drives the entire concept of backend architectures, is a request. Simply defined, a request is a message regarding the task a user wants to accomplish. They can be blocking or complex, or non-blocking or simple.
- Node.js Server: The second component is the core of the architecture, the server. The server is a server-side program that receives users' requests, processes them, and sends back relevant and expected results.
- Event Queue: Every time a request is received, it is placed in a waiting list, called the event queue. Once the required resources to process that request are available, it is moved from the event queue.
- Thread Pool: Each server has a fixed number of threads. The number of threads depends on the hardware architecture of the server. All the threads in a server are collectively called the thread pool.
- Event Loop: This is an indefinite loop. It keeps getting requests from the event queue and processes them. The response is returned to the corresponding clients.
External Resources: Lastly, we have external resources which are not native to the Node architecture but may be required by the client's request. These may include databases, file systems, etc
Diagrammatic Representation of the Node Architecture
Where is Node Architecture Used?
As discussed above, Node Architecture is unique because it solves the redundancy that existed in traditional approaches to many problems. The main issue is discussed in this section.
Resource Heavy I/O Tasks
When working with web requests, we often encounter some requests which are extraordinarily resource expensive. These requests include accessing APIs (Application Programming Interface), accessing information from databases, accessing file systems, and accessing system information are a few examples.
The Traditional Approach:
Traditionally, every request that was received was given a unique thread. That thread stuck with the request until the resource had fully completed the request. Diagrammatically, we can explain it like this:
Diagrammatic Representation of Traditional Approach
When the request is under I/O tasks, a lot of thread time is wasted waiting for the job to be completed. This is where redundancy arises in this approach.
Understanding the Traditional Approach with an example:
Imagine a new restaurant opens which wants to offer its customers the best service possible. They hire 50 waiters as the restaurant has 50 tables. Every time a customer comes, they are given a new waiter. Now, this waiter first serves them the menu but then keeps waiting while the customer decides. Then the waiter takes the order to the chef but again wastes their time while the chef prepares the food. Then the waiter serves the food and yet again wastes time till the customer finishes their meal. In this entire process, there are a lot of inefficiencies. The waiter wastes their time while the customer or chef is doing the procedure.
This approach is also relatively expensive as you have to keep as many waiters as there can be customers at any given time.
TechnicalAnalogy of the Example:
In the above-given example, we can compare waiters to threads in servers, customers to requests, and the process of eating or cooking to the expensive and time-consuming I/O task. In traditional architectures like C# or Java, each job is handled by a new thread. Since a server only has a limited number of threads, the server can work upon only a limited number of processes. This makes the entire process redundant, expensive, and inefficient.
Solving these Issues with the Node Architecture
The Node architecture is built to choose an entirely different approach to solving requests with heavy I/O tasks. To understand Node Architecture, let us take the same example of a restaurant.
In Node Architecture, the restaurant with a capacity of 50 tables hires just five waiters. Every time a new customer comes, a waiter is assigned. The waiter then seats the customer, and while the customer decides what to order, that waiter handles the needs of other customers. Then again, when food is being cooked or when the customer is eating their meal, the waiter manages other customers instead of wasting time. In this methodology, the capacity of the waiter is maximized. This way of resource optimization ensures that the cost is also low while efficiency is maximum.
How the Node Architecture Works
In the node architecture, while a request is undergoing an I/O process, the main thread automatically changes requests to cater to other requests. This approach is called an Asynchronous and Event-Based approach. An event-based architecture ensures that the main thread does not waste time when a request undergoes an I/O process.
All the Requests from the client are received on an Event Thread. Every request consists of Asynchronous and Synchronous Execution. The Main (Event) Thread is responsible for executing only the Synchronous Part of the Request. When an Asynchronous I/O Operation is encountered, the Main Thread allocates a Background thread to process the I/O Operation.
This Main Thread does not wait for time-consuming external processes to finish. While the background thread manages the I/O process, the main thread is free to take other requests. Node's main thread is almost always continuously switching requests, hence ensuring maximum efficiency.
The Node Architecture is Event-Based. This means that whenever a request completes an I/O process, the background thread uses an event-based approach to notify the main thread. Every Asynchronous task comprises a callback function. Once a job is complete, and this function is called, the background thread raises an event to notify the main thread. The request then waits till the main thread gets free, and then the main thread again takes the request further.
Frequently Asked Questions
- Is NodeJS multi-threaded?
No, NodeJS is not multi-threaded. This is because the main thread takes every new request. Then, Node, in the background, creates new background threads, which gives a multi-threaded illusion.
- What exactly do we mean by an Event?
An event is nothing but a notification fired by the background threads to notify the main thread that the expensive I/O process has now finished.