امروز : ۲۲ آذر ۱۴۰۴ (2025/12/13)

Event Loop چیست و چرا Nodejs هنگ نمی کند!

Event Loop در Node.js چگونه کار می‌کند و چرا مانع هنگ‌ کردن سیستم می‌شود؟ 

وقتی برای نخستین بار Node.js معرفی شد بسیاری از توسعه دهندگان نرم افزار از اینکه چطور یک محیط اجرای جاوااسکریپت که تنها از یک ریسمان (Thread) استفاده می کند تا این اندازه عملکرد بهتر نسبت به بسیازی از زبان ها و پلتفرم هایی دارد که چند ریسمانه می باشند تعجب کردند!

در زمان معرفی Nodejs وقتی آقای Ryan Dahl بر روی صحنه کنفرانس گفت با یک تکنولوژی تک ریسمانی می تواند وب سروری بسازد که از آپاچی و Nginx و حتی بساری از وب سرور های نوشته شده با پایتون، روبی و جاوا سریعتر هست! خیلی ها این ادعا را بیش از اندازه اغراق آمیز دانستند ولی فقط چند ماه بعد بود که شرکت های بزرگی در دنیا مانند LinkedIn ،Uber ،Netflix و PayPal شروع به مهاجرت بخش‌ های حیاتی خود به Node.js کردند و آمار واقعی عملکرد را وقتی منتشر کردند همه را شوکه کرد!

برای مثال لینکدین اعلام کرد با مهاجرت به سمت نود جی اس سرعت پاسخ درخواست های موبایل 20 برابر سریعتر شد در حالی که تعداد سرور ها از 30 عدد به 3 عدد کاهش یافت!

یا PayPal گفت سرعت بارگذاری صفحات دو برابر بهتر شد و Netflix هم گفت زمان بارگذاری app ها تا 70 درصد کاهش یافت و میلیون ها استریم ویدیو بدون هیچ مشکلی بارگذاری می شوند.

بله این تنها بخش هایی از تحولی بود که نود جی اس در دنیا ایجاد کرد.

اما واقعا در پشت صحنه چه رازی وجود داشت که نود جی اس تک ریسمانه تا این اندازه موفق عمل کرد؟ پاسخ به این پرسش در معماری این تکنولوژی قرار دارد و در یک کلمه می توان گفت: Event Loop

این مکانزیم باعث می شود نود جی اس بتواند همزمان هزاران اتصال را هندل کند بدون اینکه Thread های زیادی ایجاد کند یا مصرف حافظه را بالا ببرد!

Event Loop دقیقاً چیست؟

Event Loop در ساده‌ ترین تعریف یک حلقه بی‌ وقفه تصمیم‌ گیری است! این حلقه نه خود عملیات سنگین انجام می‌ دهد، نه منتظر می‌ ماند! بلکه کارش این است که ببیند چه چیزی آماده اجراست و در چه زمانی باید اجرا شود.

Event Loop در هر لحظه سه سوال اصلی را بررسی می‌ کند:

چه Callback هایی آماده اجرا هستند؟

چه عملیات‌ هایی باید به Thread Pool سپرده شوند؟

چه نتیجه‌ هایی از کارهای قبلی برگشته‌ اند و باید پردازش شوند؟

این مدل باعث می‌ شود که Thread اصلی هیچ وقت در انتظار عملیات‌ های طولانی متوقف نشود.

 این چرخه در طول عمر فرآیند Node.js هیچ وقت به پایان نمی رسد! مگر اینکه برنامه تمام شود یا خطای کشنده رخ دهد!

در نگاه اول شاید تک ریسمانه بودن نود جی اس یک نقطه ضعف تلقی می شد اما وقتی به این معماری نگاه می کنیم این مورد نه تنها یک نقطه ضعف نیست بلکه از دلایل اصلی محبوبیت این تکنولوژی محسوب می شود!

تک‌ ریسمانه بودن به معنای سادگی مدیریت و کاهش هزینه هم‌ زمانی است، به شرطی که یک مکانیزم قوی برای اجرای غیر همزمان وجود داشته باشد. این مکانیزم همان Event Loop است.

باید این نکته را در نظر داشته باشید که تک ریسمانه بودن به این معنا که نود جی اس نمی تواند چندین کار را همزمان انجام دهد نیست و در واقعیت نود جی اس تنها در سطح اجرای جاوااسکریپت تک ریسمان می باشد و در پشت صحنه عملیات های دیگر توسط Libuv و Thread Pool اختصاصی آن یا توسط سیستم عامل انجام می شود.

اما چند ریسمانی سنتی واقعا چه نقاط ضعفی داشت که باعث پیشرفت چشم گیری نود جی اس میان توسعه دهندگان شد!

چرا مدل سنتی چند ریسمانی در عمل مشکل دارد؟

در معماری های قدیمی وب سرور ها برای هر اتصال ورودی یک پردازش یا Thread جداگانه ایجاد می کردند و این مورد در زمان خود شاید ساده و ابتدایی به نظر می رسید و منطقی هم بود! اما در عمل هزینه های سنگینی به سرور تحمیل می کرد و منابع سرور را به شدت درگیر می ساخت.

به طور خلاصه اگر بخواهیم مشکلات مدل سنتی چند ریسمانه را بگوییم:

1-مصرف بسیار بالای حافظه برای هر ریسمان:

هر Thread معموما بین 1 تا 8 مگابایت حافظه سیستم را برای Stack رزرو می کند. حالا تصور کنید که قرار است سرور هزاران اتصال همزمان را مدیریت کند طبیعی هست مصرف حافظه به صورت تصاعدی افزایش می یابد و به راحتی به چند گیگابایت می رسد. بنابراین وب سرور های قدیمی در درخواست های بالا بدون اینکه حتی نیاز به کار خاصی باشد (اکثر درخواست ها در انتظار پاسخ هستند و در لحظه کاری نمی کنند ) مصرف بالایی را به سرور تحمیل می کنند.

2- اعمال فشار روی منابع سرور بابت جابه جایی بین ریسمان ها!

سیستم عامل برای جابه جایی بین Thread های مختلف مجبور است هر بار وضعیت هر Thread را ذخیره و بازیابی کند! وقتی سیستم کوچک هست و درخواست ها هم پایین هست این مورد هیچ مشکلی ایجاد نمی کند اما وقتی Thread های فعال به هزاران عدد می رسد اینجا فشار برای CPU سرور به شدت بالا می رود و طبیعی هست سرور دیگر قدرت پاسخگویی خود را از دست می دهد.

3- در انتظار بودن (Idle) بودن بیشتر Threadها:

در زمان ترافیک واقعی و مصرف بالا اکثر درخواست ها در حال انجام محاسبات سنگین نیستند و معمولا در حال انتظار برای I/O هستند! مثلا زمانی که منتظر پاسخ پایگاه داده یا درخواست های یک API خارجی می باشند. حتی وقتی قرار است یک فایل از دیسک خوانده شود بنابراین در 99٪ مواقع Thread ها در واقع بیکارند و تنها منابع سیستم را درگیر خود می کنند و کارایی را کاهش می دهند.

4- مشکل Thread های متعدد روی یک منبع مشترک:

وقتی هزاران Thread قرار است به یک منبع مشترک مانند Connection Pool پایگاه داده یا Cache مشترک دسترسی پیدا کنند برای جلوگیری از بروز مشکل، خرابی داده و یا حتی اشتباه در نتیجه نهایی سیستم به ناچار باید قفل گذاری انجام دهد و هر بار که پردازش یک Thread به اتمام رسید سی پیو وضعیت Thread را آزاد کند و به Thread دیگر اجازه می دهد وارد سیستم شود  همین قفل ها و آزاد شدن مکرر باعث مصرف بالای منابع سخت افزاری می شود و به همین دلیل سیستم های چند ریسمانی در مقیاس بالا ناکارآمد و سنگین می باشند.

این ها بخش هایی از ضعف هایی بود که سیستم های چند ریسمانه در ورودی های بالا با آن رو به رو بودند و به همین دلایل باعث محبوبیت بیشتر نود جی اس شد.

Node.js و تک‌ ریسمانه‌ سازی منطق، چند ریسمانه‌ سازی I/O:

Ryan Dahl یک ایده بسیار ساده و موثر داشت و آن هم این بود که بسیاری از درخواست های وب در حال I/O هستند و هیچ محاسبه ای را انجام نمی دهند! پس چرا هر کدام باید یک Thered مجزا باشند!

بنابراین فکری که به ذهنش رسید می توان گفت در نهایت به یک تحول بزرگ انجامید!

منطق برنامه  یا همان کدهای  JavaScript روی یک Event Loop تک‌ ریسمانه اجرا می‌ شود که این باعث ساده‌ شدن هم‌ زمانی برای برنامه‌ نویس می‌شود.

عملیات I/O و برخی کارهای سنگین به‌ صورت غیر بلاک‌ کننده و اغلب توسط یک Thread Pool یا خود سیستم‌ عامل انجام می‌ شوند در واقع در این بخش از قابلیت‌ های چند ریسمانه بهره می‌ برد تا کارایی واقعی را نگه دارد.

برای فهم بهتر می توان نود جی اس را به عنوان یک مدیر تشبیه کرد که خودش هیچ کاری انجام نمی دهد و فقط دستور می دهد تا کاری صورت بگیرد و بدون اینکه منتظر اتمام کار باشد به سراغ کارهای دیگر و دستورات بعدی می رود! در مدل های قدیمی این دستورات بعد ارسال باید منتظر پاسخ می ماندند تا بعد پاسخ به سراغ دستور بعدی بروند و همین تفاوت بزرگ هست که نود جی اس را در مقایسه با سایر سیستم ها تا این اندازه کارآمد کرده است.

مزیت های معماری تک ریسمانه نود جی اس چیست؟

معماری Node.js بر پایه‌ ی یک Event Loop تک‌ ریسمانه ساخته شده است یعنی تمام کد JavaScript در یک Thread اجرا می‌ شود و عملیات I/O در پس‌ زمینه به‌ صورت غیر هم‌ زمان مدیریت می‌ شوند.

این انتخاب معماری چند مزیت مهم و کاربردی ایجاد کرده که باعث محبوبیت Node در ساخت سرویس‌ های سریع و مقیاس‌پذیر شده است.

1- مصرف حافظه بسیار کم:

چون برای اتصال ها دیگر ریسمان مجزا ایجاد نمی شود نود جی اس در عمل می تواند با مقدار کمی RAM هزاران اتصال را پشتیبانی کند. دیگر حافظه قرار نیست برای اتصال های Idle و بیکار فضایی را اختصاص دهد و منابع را رزرو کند!

در عمل فقط یک Thread برای اجرای جاوااسکریپت وجود دارد و سایر کارها توسط Thread Pool یا سیستم‌ عامل مدیریت می‌ شوند.

2- حل تداخلات ناشی از همزمانی!

مشکلی که در سیستم های چند ریسمانی بخاطر کار روی یک منبع مشترک می توانست رخ دهد و داده ها را دچار مشکل کند و به ناچار از سیستم قفل استفاده می کردند در نود جی اس به طور کامل برطرف شد!

چون تمام کدها JS روی یک Thread اجرا می شدند و این باعث می شد هیچگاه همزمان دو کد به یک متغییر دست نزند! و این باعث جلوگیری از مشکلات احتمالی و بی نیاز شدن از سیستم های Lock می شود که خود این مورد مصرف سی پیو را به طرز چشم گیری کاهش می دهد.

3- توانایی پاسخگویی به تعداد درخواست های بالا همزمان!

حتی با یک سخت افزار متوسط هم می توان ده ها هزار درخواست را مدیریت کرد و علت آن هم خیلی ساده می باشد زیرا اتصالات Idle هیچ Thread سنگینی اشغال نمی‌ کنند.

در نتیجه مصرف روی رم و سی پیو کاهش می یابد و همین مورد باعث افزایش سرعت پاسخگویی به درخواست ها می شود.

4- مقایس پذیری طبیعی و ساده:

به دلیل ماهیت Non-Blocking I/O نود جی اس، فشار واقعی روی CPU کاهش می‌یابد. و Event Loop به سرعت سراغ کار بعدی می رود در نتیجه زمانی هدر نمی رود پس اگر درخواست ها افزایش هم یابد در عمل تفاوتی ایجاد نمی کند و سرور می تواند بدون تغییرات خاصی درخواست های جدید را هم طبیعی هندل کند و در سیستم هایی با ورودی بالا این مورد بسیار کمک کننده هست.

همین فلسفه های نود جی اس باعث شده که رم بسیار کم مصرف کند، مشکلات رقابت هم‌ زمان را حذف کند، هزاران اتصال را بدون فشار پردازش کند و بدون پیچیدگی‌ های Thread-Based مقیاس‌پذیر باقی بماند

به همین دلیل است که Node انتخاب محبوبی برای سرویس‌ های مدرن و real-time شده است.

با توجه به مواردی که گفته شد می توان پیش بینی کرد که نود جی اس نباید هنگ کند! اما واقعا چرا؟

چرا Node.js هنگ نمی‌ کند؟

به صورت خلاصه و روان می توان گفت وقتی یک عملیات I/O رخ می دهد نود جی اس منتظر نمی ماند! بلکه این درخواست را به سیستم عامل یا thread pool می سپارد و خودش را آزاد می کند تا به بقیه درخواست ها رسیدگی کند باعث می شود هیچگاه نود جی اس هنگ نکند.

مستند رسمی Node.js تأکید می‌ کند اگر فقط callback های کوتاه و سبک در Event Loop داشته باشید و از توابع sync یا محاسبات سنگین دوری کنید، سیستم روان و responsive باقی می‌ ماند.

عدم مسدود سازی یا همان Non-Blocking I/O دلیل اصلی پایداری نود جی اس می باشد چون اگر هزار کاربر هم درخواست خواندن یک فایل را ارسال کنند نود جی اس دچار فشار Thread نمی شود و اگر صدها اتصال WebSocket باز باشد هم Thread اصلی قفل نمی شود.

اگر درخواست ها پشت سرهم رخ بدهند Event Loop همیشه آماده پاسخ‌ دهی است.

به همین دلایل هست که نود جی اس برای برنامه های زیر مناسب هست:

سیستم‌ های real-time

API های پرمصرف

پیام‌ رسان‌ها

استریم ویدیو

وب‌سرور ها با ترافیک بالا

در چه شرایطی نود جی اس هنگ می کند؟

اگر قرار باشد محاسبات سنگین که به مصرف سی پیو بالا نیاز دارند یا رمزنگاری ها طولانی و حلقه های پی در پی به نود جی اس واگذار شود این باعث می‌شود Event Loop نتواند ادامه دهد و نود جی اس هنگ خواهد کرد.

با اینکه Event Loop جلوی اکثر موارد انسداد را می‌ گیرد، Node.js همچنان در برابر گروه هایی که سی پیو محور هستند و پردازش های سنگین دارند آسیب‌ پذیر هستند مانند پردازش صدا و تصویر!

بنابراین اگر نود جی اس برای پروژه هایی استفاده شود که فقط قرار است پاسخگویی سریع به درخواست ها بدون مصرف بالای سی پیو و پردازش های سنگین داشته باشند یک عملکرد فوق العاده از خود به نمایش خواهد گذاشت.

نتیجه گیری:

Event Loop مهم‌ ترین بخش معماری Node.js است که ساز و کاری که باعث می‌ شود تک‌ ریسمانه بودن نه محدودیت بلکه مزیت باشد.

با تفکیک مدیریت رویداد  ها از اجرای عملیات سنگین، Node.js می‌تواند هزاران درخواست را بدون هنگ‌ کردن مدیریت کند. این مدل باعث شده نود جی اس به گزینه‌ ای ایده‌ آل برای برنامه‌ های مدرن تبدیل شود به‌ خصوص جایی که نیاز به سرعت بالا، مصرف کم منابع و هم‌ زمانی زیاد وجود دارد .

در نهایت اگر برنامه‌نویس اصول معماری Node.js را صحیح رعایت کند و عملیات‌های CPU-Heavy را روی Thread اصلی اجرا نکند، Event Loop تضمین می‌ کند که سیستم همیشه روان، سریع و قابل‌ اعتماد باقی بماند.

اگر شما هم شیفته کار کردن با نود جی اس و راه اندازی سامانه ها و پروژه های خود با این تکنولوژی هستید به شما هاست نود جی اس پارس وب سرور را پیشنهاد می کنیم.

در این هاست ها شما با دسترسی داشتن به محیط ترمینال برای مشاهده لاگ های لحظه ای و فعالسازی سوکت و اختصاص یافتن یک پورت آزاد به پروژه به سادگی می توانید  پروژه خود را بدون مشکل و دردسرهای کانفیگ سرور روی هاست راه اندازی کنید.

Rate this post