সবার আগে শুরু করি Node.js এর ক্লেইম করা একটা লাইন দিয়ে “Node.js is designed to build scalable network applications”।
Node.js ডিজাইন করা হয়েছে scalable network application এর জন্য, আমরা নরমাল্লি ও শুনে থাকি Node.js is highly scalable, কিন্তু কি ভাবে ??
আজকে সেঁটা নিয়ে আলোচনা করবো এবং কিছু কোড সহ দেখানোর চেষ্টা করবো। শুরু করার আগে একটু কথা বলে নেই, থ্রেড বেসড নেটওয়ার্কিং তুলনামূলক ভাবে কম ইফিশিএন্ট এবং মানেজ করা একটু কঠিন।
সেখানে Dead-lock, process blocking এসব জিনিসের কিছু প্যারা থেকে যায়, কিন্তু Node.js এ process dead lock হওয়ার সম্ভাবনা ও নাই, কারণ Node.js সিঙ্গেল থ্রেড এ রান করে।
আরেকটা মজার ব্যাপার হল কোন ফাংশন এর I/O operation সরাসরি Node.js এ এক্সিকিউট হয়না, সুতরাং প্রসেস ব্লক হয়ে যাওয়ার চিন্তা মুক্ত থাকতে পারি আমরা।
ওহ আচ্ছা আরেকটা কথা, Node.js রান করে সিঙ্গেল থ্রেড এ, তার মানে এইটা না যে আপনি multi thread অথবা আপনার ইনভারন্মেন্ট এর multiple core এর advantage নিতে পারবেন না। child_process তৈরি করে আমরা এই advantage গুলা নিতে পারি।
এতক্ষণ তো অন্য কথা বললাম এইবার আসি মুল আলোচনায়। 😄
আজকে আমি cluster module দিয়ে বুঝানোর চেষ্টা করবো কিভাবে Node.js application scale করা যায়।
Cluster module
Node.js এর built in modules দিয়ে দেখানোর চেষ্টা করব কি ভাবে একটা single multicore machine এ horizontally scale করা যায়।
ধরে নেই আমার একটা multicore system আছে, আমার node application কে fork করে প্রত্যেক core এ রান করে load balancing এর মাধ্যমে request গুলোকে সব core এ distribute করলেই কেল্লাফতে 😇, তাহলেই আমরা horizontally scal করতে পারব আমাদের application কে, চলুন তাহলে দেখা যাক কি ভাবে করা যায়।
এই পুরো কাজটা cluster module দিয়ে করা সম্ভব, তোহ এখন তাহলে একটু দেখে আসি cluster module কিভাবে সাহায্য করতে পারে আমাদের।
cluster module এর সাহায্যে child procss create করে node applicaiton কে multi core এ run করতে পারব।
তাহলে child process তৈরি করার পরে আমাদের একটা master process এবং কিছু child process থাকবে এবং master and child process তাদের মধ্যে communicatoin করে IPC (Inter Process Communication channel) এর মাধ্যমে।
আর request distribute করার জন্য round-robin algorithm ব্যবহার করে cluster module।
const cluster = require('cluster');
const http = require('http');
// number of cpu cores
const numberOfCPU = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master is running: ${process.pid}`);
// Fork workers.
for (let i = 0; i < numberOfCPU; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code) => {
console.log(`worker ${worker.process.pid} died`);
// to increase the availability of the application
// we create new worker using fork() method if the worker is crushed.
// so that we can increase our applications availability.
if (code !== 0 && !worker.exitedAfterDisconnect) {
console.log(`Worker ${worker.id} crashed. \nStarting a new worker...`);
cluster.fork();
}
});
} else {
// Create a HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(4000);
console.log(`Worker ${process.pid} started`);
}

নিচে একটা স্যাম্পল কোড এর উদাহরণ দিয়ে cluster module এর পার্ট শেষ করবো।
const cluster = require('cluster');
const http = require('http');
// number of cpu cores
const numberOfCPU = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master is running: ${process.pid}`);
// Fork workers.
for (let i = 0; i < numberOfCPU; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code) => {
console.log(`worker ${worker.process.pid} died`);
// to increase the availability of the application
// we create new worker using fork() method if the worker is crushed.
// so that we can increase our applications availability.
if (code !== 0 && !worker.exitedAfterDisconnect) {
console.log(`Worker ${worker.id} crashed. \nStarting a new worker...`);
cluster.fork();
}
});
} else {
// Create a HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(4000);
console.log(`Worker ${process.pid} started`);
}

আমার machine এর ৮ টা core, এ জন্য total ৮ টা worker run করতেছে আমার application এর।
এখন application এর availability বাড়ানোর জন্য আমরা একটা কাজ করতে পারি, সেটা হল যখন কোন worker dead হয়ে যাবে তখন আমরা আরেকটা নতুন worker create করে ফেললেই আমরা আমাদের application এর availability বাড়াতে পারব।
// to increase the availability of the application
// we create new worker using fork() method if the worker is crushed.
// so that we can increase our applications availability.
if (code !== 0 && !worker.exitedAfterDisconnect) {
console.log(`Worker ${worker.id} crashed. \nStarting a new worker...`);
cluster.fork();
}
এছাড়া ও zero downtime restart ও সম্ভব cluster module এর সাহায্যে, এটা অন্য একদিন লিখব, আজকে এ পর্যন্তই cluster module নিয়ে।
পরবর্তী আর্টিকেল এ cluster module নিয়ে আরেকটু ডিটেইল আলোচনা করবো সাথে থাকবে PM2 নিয়ে বিস্তারিত।
[বিঃদ্রঃ ভুলত্রুটি থাকলে কমেন্ট করে জানাবেন, অবশ্যই ঠিক করার চেষ্টা করবো, আর কিছু ইম্প্রুভ এর থাকলে ও জানাবেন]