Using the Node.js Cluster Module to Improve Server Performance
As a former 3D Animator with more than 12 years of experience, I have always been fascinated by the intersection of technology and creativity. That's why I recently shifted my career towards MERN stack development and software engineering, where I have been serving since 2021.
With my background in 3D animation, I bring a unique perspective to software development, combining creativity and technical expertise to build innovative and visually engaging applications. I have a passion for learning and staying up-to-date with the latest technologies and best practices, and I enjoy collaborating with cross-functional teams to solve complex problems and create seamless user experiences.
In my current role as a MERN stack developer, I have been responsible for developing and implementing web applications using MongoDB, Express, React, and Node.js. I have also gained experience in Agile development methodologies, version control with Git, and cloud-based deployment using platforms like Heroku and AWS.
I am committed to delivering high-quality work that meets the needs of both clients and end-users, and I am always seeking new challenges and opportunities to grow both personally and professionally.
Welcome back.
Now that we understand the theory behind clustering, let's explore how to apply the Node.js cluster module to our servers and improve their performance. In this document, we'll modify our performance example code to create two worker processes that handle requests concurrently.
Step-by-Step Guide to Implement Clustering
1. Requiring the Cluster Module
To use the cluster module, start by requiring it in your server file:
const cluster = require('cluster');
2. Master and Worker Processes
When you execute your Node.js application (e.g., node server.js), a master process is created. This master process is responsible for creating worker processes.
The master and worker processes can be distinguished using the isMaster boolean property provided by the cluster module:
if (cluster.isMaster) { //in new versions it is cluster.isPrimary
console.log('Master process has started.');
// Fork workers
cluster.fork();
cluster.fork();
} else {
console.log('Worker process has started.');
// Code for worker processes (e.g., starting the server)
}
3. Forking Worker Processes
To create worker processes, call the cluster.fork() method. Each call creates a new worker process:
if (cluster.isMaster) { //in new versions it is cluster.isPrimary
cluster.fork();
cluster.fork();
}
In this example, we fork two worker processes. Each worker runs the same code as the master process but focuses on handling incoming HTTP requests.
4. Listening in Worker Processes
Only the worker processes should start the server and listen for incoming requests. Use the isMaster property to ensure this separation:
import express from 'express';
import cluster from 'cluster';
const app = express();
app.get('/route', (req, res) => {
res.send(`Route handled by process ${process.pid}`);
});
app.get('/timer', (req, res) => {
setTimeout(() => {
res.send(`Timer completed by process ${process.pid}`);
}, 9000);
});
if (cluster.isPrimary) {
console.log(`Master ${process.pid} is running`);
// Fork workers
cluster.fork();
cluster.fork();
} else {
console.log(`Worker ${process.pid} started`);
app.listen(3000, () => {
console.log(`Worker ${process.pid} is listening on port 3000`);
});
}
5. Testing Process IDs
To verify which process handles a specific request, use the process.pid property. This will log the ID of the current process to demonstrate load sharing.
Running the Clustered Server
Start the server:
node server.jsYou’ll see logs indicating the master process and the two workers have started:
Master process has started. Worker process 24730 has started. Worker process 24731 has started.Open multiple browser tabs or use tools like Postman to send simultaneous requests to the
/timerand/routeendpoints.Requests to
/timerwill take 9 seconds to complete but will be handled by different processes.Requests to
/routewill be processed immediately by whichever worker process is available.
Handling Browser Caching Issues
When testing server clustering, browsers like Chrome might reuse cached responses for identical requests. To avoid this:
Open the browser’s Developer Tools.
Navigate to the Network tab.
Enable the Disable Cache option.
Alternatively, use keyboard shortcuts (e.g.,
Ctrl+Shift+RorCmd+Shift+R) to refresh without caching.
Observing the Results
Send requests to
/timerfrom two browser tabs:Both requests should take 9 seconds but be processed in parallel by different worker processes.
Logs will display different
process.pidvalues for each request.
Send a request to
/routewhile a/timerrequest is being processed:- The
/routerequest will return almost instantly, demonstrating that the server remains responsive.
- The
Example logs:
Master process has started.
Worker process 24730 has started.
Worker process 24731 has started.
Route handled by process 24730
Timer completed by process 24731
Key Takeaways
The Node.js cluster module allows single-threaded applications to utilize multiple CPU cores effectively.
Worker processes share the workload, improving the server’s responsiveness and performance.
The
isMasterflag ensures code segregation between the master and worker processes.
In the next lesson, we’ll discuss best practices for using clustering in real-world applications. See you soon!