Problems With Single Threaded Server
⚠️ ২. Single-threaded Server এর সমস্যা:
- যদি একটি কাজ অনেক সময় নেয় (যেমন: বড় ফাইল পড়া), তখন সার্ভার আটকে যায়।
- সার্ভার তখন অন্য ক্লায়েন্টের রিকোয়েস্ট নিতে পারে না।
- Heavy CPU কাজ সার্ভার ব্লক করে ফেলে।
💻 ৩. I/O Operation vs CPU Operation
| Operation | বর্ণনা | উদাহরণ |
|---|---|---|
| I/O-bound | Input/Output কাজ, যা অপেক্ষা করে (waiting) | ফাইল পড়া, নেটওয়ার্ক রিকোয়েস্ট, ডেটাবেজ কোয়েরি |
| CPU-bound | অনেক প্রসেসিং লাগে, CPU চাপে থাকে | Image Processing, Encryption, লজিক্যাল ক্যালকুলেশন |
🚀 ৪. Node.js কীভাবে এই সমস্যার সমাধান করে?
Node.js তার সিঙ্গেল-থ্রেডেড নেচার থাকা সত্ত্বেও অ্যাসিঙ্ক্রোনাস অপারেশনগুলো দক্ষতার সাথে পরিচালনা করে Event Loop, libuv লাইব্রেরি এবং একটি Thread Pool এর সম্মিলিত ব্যবহারের মাধ্যমে। এটি অ্যাপ্লিকেশনকে নন-ব্লকিং রাখতে এবং উচ্চ-পারফরম্যান্স বজায় রাখতে সাহায্য করে।
✅ সমাধানের পদ্ধতি:
১. নন-ব্লকিং I/O: Node.js এর ভিত্তি
Node.js এর মূল শক্তি হলো এর নন-ব্লকিং ইনপুট/আউটপুট (I/O) মডেল।
এর মানে হলো, যখন একটি I/O অপারেশন (যেমন ফাইল রিড/রাইট, নেটওয়ার্ক রিকোয়েস্ট) শুরু হয়, তখন Node.js মূল থ্রেডকে ব্লক না করে সেই কাজটিকে ব্যাকগ্রাউন্ডে পাঠিয়ে দেয়।
মূল থ্রেড তখন অন্য রিকোয়েস্ট বা কাজ নিতে সম্পূর্ণ ফ্রি থাকে।
২. Event Loop: Node.js এর হার্ট
Event Loop হলো Node.js এর রানটাইমের মূল অংশ।
এটি একটি অনন্ত লুপ যা ক্রমাগত দুটি জিনিসের দিকে নজর রাখে:
- Call Stack: এটি জাভাস্ক্রিপ্ট কোডের এক্সিকিউশন স্ট্যাক। যখন কোনো ফাংশন কল হয়, তা স্ট্যাকে যোগ হয় এবং এক্সিকিউশন শেষ হলে স্ট্যাক থেকে পপ হয়ে যায়।
- Callback Queue (এবং Microtask Queue): যখন একটি অ্যাসিঙ্ক্রোনাস অপারেশন সম্পন্ন হয়, তখন এর সাথে যুক্ত কলব্যাক ফাংশনগুলো একটি লাইনে (কিউ) জমা হয়।
ইভেন্ট লুপের কাজ:
- যখন Call Stack খালি থাকে, তখন ইভেন্ট লুপ
Callback Queueথেকে পরবর্তী কলব্যাক ফাংশনটি নেয়। - এই কলব্যাক ফাংশনটিকে
Call Stackএ পুশ করে এক্সিকিউট করার জন্য। - এটি নিশ্চিত করে যে আপনার জাভাস্ক্রিপ্ট কোড (যা সিঙ্গেল-থ্রেডে চলে) কখনই I/O অপারেশনের জন্য আটকে থাকে না।
৩. libuv: অ্যাসিঙ্ক্রোনাস ম্যাজিকের পেছনে
libuv হলো একটি C লাইব্রেরি যা Node.js এর অ্যাসিঙ্ক্রোনাস I/O এবং ইভেন্ট-চালিত আর্কিটেকচারের মূল ভিত্তি।
এটি অপারেটিং সিস্টেমের অ্যাসিঙ্ক্রোনাস ক্ষমতাগুলোকে ব্যবহার করে এবং প্ল্যাটফর্ম-নিরপেক্ষ উপায়ে অ্যাসিঙ্ক্রোনাস অপারেশনগুলো হ্যান্ডেল করে।
libuv মূলত দুটি ভিন্ন কৌশল ব্যবহার করে I/O অপারেশন পরিচালনা করে:
- অপারেটিং সিস্টেমের অ্যাসিঙ্ক্রোনাস API (OS Async API):
- বেশিরভাগ নেটওয়ার্ক I/O (যেমন - HTTP রিকোয়েস্ট, সকেট কানেকশন) অপারেটিং সিস্টেমের নিজস্ব নন-ব্লকিং অ্যাসিঙ্ক্রোনাস API ব্যবহার করে।
libuvসরাসরি এই API-গুলির সাথে ইন্টারঅ্যাক্ট করে। এই অপারেশনগুলো থ্রেড পুলে যায় না, কারণ OS নিজেই এগুলি নন-ব্লকিং উপায়ে হ্যান্ডেল করতে পারে এবং কাজ শেষ হলেlibuvকে অবহিত করে।
- Thread Pool (থ্রেড পুল):
- কিছু নির্দিষ্ট ধরনের I/O অপারেশন ব্লকিং প্রকৃতির হতে পারে, অর্থাৎ এগুলি শেষ হতে যথেষ্ট সময় লাগতে পারে এবং মূল থ্রেডকে আটকে রাখতে পারে।
- এই ধরনের কাজগুলোর জন্য (
libuvদ্বারা পরিচালিত), যেমন:- ফাইল সিস্টেম অপারেশন (ফাইল রিড, রাইট)
- DNS লুকআপ
- কিছু ক্রিপ্টোগ্রাফিক অপারেশন
libuvএকটি অভ্যন্তরীণ থ্রেড পুল ব্যবহার করে। এই থ্রেড পুলে সাধারণত ৪টি ওয়ার্কার থ্রেড থাকে (যদিও এটি কনফিগার করা যায়)।libuvএই ব্লকিং কাজগুলোকে থ্রেড পুলের একটি থ্রেডে পাঠিয়ে দেয়। থ্রেডটি ব্যাকগ্রাউন্ডে কাজটি সম্পন্ন করে এবং কাজ শেষ হলেlibuvকে জানায়, যা পরবর্তীতে সংশ্লিষ্ট কলব্যাককেCallback Queueএ যোগ করে।
৪. মূল থ্রেড (Event Loop) এর স্বাধীনতা
যখন libuv তার থ্রেড পুল বা OS Async API ব্যবহার করে I/O কাজগুলো ব্যাকগ্রাউন্ডে পরিচালনা করে, তখন Node.js এর মূল থ্রেড (যেখানে Event Loop চলে) সম্পূর্ণ ফ্রি থাকে। এটি অন্য ইউজার রিকোয়েস্ট বা জাভাস্ক্রিপ্ট কোড এক্সিকিউট করতে পারে, যার ফলে Node.js উচ্চ কনকারেন্সি (একই সময়ে অনেকগুলো কাজ হ্যান্ডেল করার ক্ষমতা) অর্জন করতে পারে।