Node.js Advanced Architecture — Scaling Beyond the Single Thread
"Scaling Beyond the Single Thread"
Node.js এর সবচেয়ে বড় শক্তি এবং দুর্বলতা একই—এটি Single Threaded।
শক্তি: এটি I/O (Database, Network) এর জন্য সুপার ফাস্ট।
দুর্বলতা: এটি CPU Heavy (Image Processing, Calculation) কাজে মেইন থ্রেড ব্লক করে দেয়।
একজন সিনিয়র ইঞ্জিনিয়ার হিসেবে তোমাকে জানতে হবে কিভাবে এই লিমিটেশন ভাঙতে হয়।
⭐ ১. Node.js Internals: মিথ বনাম সত্য 🕵️♂️
🔷 Myth vs Truth:
- Myth: Node.js পুরোপুরি সিঙ্গেল থ্রেডেড
- Truth: জাভাস্ক্রিপ্ট (V8) সিঙ্গেল থ্রেডেড, কিন্তু Node.js রানটাইম (Libuv) মাল্টি-থ্রেডেড
🏗️ The Architecture:
- Event Loop (The Manager): ১ জন। সে কাজ রিসিভ করে এবং ডিস্ট্রিবিউট করে
- Worker Pool (The Staff - Libuv): বাই ডিফল্ট ৪ জন
💡 Senior Tip: process.env.UV_THREADPOOL_SIZE = 16; দিয়ে ওয়ার্কার সংখ্যা বাড়ানো যায়
⭐ ২. The Problem: CPU Bottleneck ⚠️
app.get("/heavy", (req, res) => {
// এই লুপ চলাকালীন সার্ভার অন্য কোনো রিকোয়েস্ট নিতে পারবে না!
let sum = 0;
for (let i = 0; i < 1e10; i++) sum += i;
res.send({ sum });
});
⚠️ সমাধান: Worker Threads অথবা Cluster
⭐ ৩. Worker Threads: True Multithreading 🧵
🎯 কখন ব্যবহার করব?
- ইমেজ রিসাইজ/প্রসেসিং
- ভিডিও এনকোডিং
- বিশাল JSON পার্সিং
- ক্রিপ্টোগ্রাফি/এনক্রিপশন
📄 main.js (Manager)
const { Worker } = require("worker_threads");
function runService(workerData) {
return new Promise((resolve, reject) => {
const worker = new Worker("./worker.js", { workerData });
worker.on("message", resolve);
worker.on("error", reject);
});
}
async function run() {
const result = await runService("Hello");
console.log(result);
}
run();
🛠️ worker.js (The Labor)
const { parentPort, workerData } = require("worker_threads");
let sum = 0;
for (let i = 0; i < 1e9; i++) sum += i;
parentPort.postMessage({ result: sum, msg: workerData });
⭐ ৪. Cluster Module: Traffic Scaling 🚦
তোমার কম্পিউটারে যদি ৮ কোরের প্রসেসর থাকে, আর তুমি ১টা Node.js প্রসেস চালাও, তবে তুমি ৭টা কোর অপচয় করছ। Cluster প্রতিটি কোরে একটি করে অ্যাপের কপি (Fork) রান করে।
const cluster = require("cluster");
const http = require("http");
const os = require("os");
if (cluster.isMaster) {
const cpus = os.cpus().length;
console.log(`Master fork for ${cpus} CPUs`);
for (let i = 0; i < cpus; i++) cluster.fork();
cluster.on("exit", (worker) => {
console.log(`Worker ${worker.process.pid} died. Restarting...`);
cluster.fork();
});
} else {
http.createServer((req, res) => {
res.end(`Hello from Worker ${process.pid}`);
}).listen(8000);
}
✅ The Enterprise Way: PM2
pm2 start app.js -i max # সব কোরে অ্যাপ রান করো
⭐ ৫. Streams: Handling Big Data 🌊
১ জিবি ফাইল - Without Stream: পুরো র্যামে লোড করবে (Crash)। With Stream: ছোট ছোট Chunk আকারে ডাটা পাঠাবে।
const fs = require("fs");
const server = require("http").createServer();
server.on("request", (req, res) => {
// ❌ Bad: fs.readFile("big.mp4", (err, data) => res.end(data));
// ✅ Senior Way: Stream
const src = fs.createReadStream("big.mp4");
src.pipe(res); // পাইপ দিয়ে ডাটা ফ্লো করে দিচ্ছি
});
📚 Backpressure: Node.js এর pipe অটোমেটিক হ্যান্ডেল করে—যতটুকু লিখতে পারবে ততটুকুই পড়বে
📊 ৬. Worker vs Cluster (Comparison)
| Feature | Worker Threads | Cluster |
|---|---|---|
| উদ্দেশ্য | CPU Intensive Task | Traffic Scaling |
| Memory | মেমোরি শেয়ার করে | আলাদা মেমোরি |
| Communication | postMessage | IPC |
⭐ ৭. Real World Architecture: How Companies Scale 🏢
- 🌐 Nginx: Reverse Proxy
- 🚀 PM2 Cluster: রিকোয়েস্ট ভাগ করে দেয়
- 🧵 Worker Threads: ইমেজ প্রসেসিং, PDF জেনারেশন
- ⚡ Redis: সেশন এবং ক্যাশিং (Cluster মোডে মেমোরি শেয়ার হয় না)
- 📧 BullMQ: ভারী কাজের জন্য Job Queue
🧠 ৮. Senior Interview Questions
Q1: process.nextTick vs setImmediate?
A: nextTick (Microtask) → Check Phase এর আগে, setImmediate (Macrotask) → Check Phase এ
Q2: ক্লাস্টার মোডে সেশন ম্যানেজ করব কিভাবে?
A: Redis বা Database ব্যবহার করতে হবে (মেমোরি শেয়ার হয় না)
Q3: স্ট্রিম এবং বাফারের পার্থক্য কী?
A: Buffer = ফিক্সড সাইজের মেমোরি চাঙ্ক, Stream = ডাটার প্রবাহ
🚀 অধ্যায় ২৭ সারাংশ (Checklist)
- ✓Internals: Libuv এবং Threadpool
- ✓CPU Scale: Worker Threads
- ✓App Scale: Cluster এবং PM2
- ✓Data Scale: Streams