5.2الأداء والعنقدة (clustering) وتوسيع النطاق
الأساسي في 30 ثانية
- أحادي الخيط : عملية Node واحدة لا تستعمل إلا نواة واحدة — والعنقدة (clustering) (وحدة cluster أو PM2) تشغّل نسخة لكل نواة.
- التخزين المؤقت أولا : خزّنوا النتائج المكلفة مؤقتا (الذاكرة أو Redis) — وهو غالبا الرافعة الأعلى أثرا.
- قيسوا قبل أن تحسّنوا : نمّطوا للعثور على الاختناقات الحقيقية — أبدا أي تحسين مبكر.
حالة مصغرة متسلسلة — ساليم يستوعب الحمل في الجزائر
واجهة ساليم المنمطة في الجزائر بدأت تتباطأ : صفحة استقبال المتجر تتأخر في الاستجابة ساعات الذروة. وبدلا من إعادة كتابة كل شيء، يقيس : استعلامات الفهرس تعود بلا انقطاع والقاعدة تُستدعى عبثا. يفعّل العنقدة لاستغلال نوى الخادم ويخزّن الفهرس مؤقتا. تتمة الحالة 5.1 — يحسّن ساليم ما قاسه، لا عشوائيا.
تتمة الحالة 5.1 — يطبق ساليم القاعدة الذهبية : القياس أولا، ثم التحسين.
1. العنقدة وخيوط العمال
Node أحادي الخيط : العملية الواحدة لا تستعمل إلا نواة واحدة، بينما الخوادم فيها عدة نوى. والعنقدة (clustering) (الوحدة الأصلية cluster أو PM2) تشغّل عدة نسخ من التطبيق (نسخة لكل نواة) تتقاسم الطلبات — مستغلة كل النوى. يضيف PM2 إعادة التشغيل التلقائي والمراقبة والسجلات. أما خيوط العمال (worker threads) فتنفذ المهام الثقيلة على المعالج (حسابات ثقيلة تحجب حلقة الأحداث) على خيوط منفصلة. يشغّل ساليم واجهته في وضع العنقدة : فتتضاعف السعة دون تغيير سطر واحد من المنطق.
المنعكس : إذا كانت عملية واحدة تدور على آلة متعددة النوى، فموارد نائمة — والعنقدة هي التوسيع العمودي المعياري لـ Node.
2. الروافع التي تؤتي
روافع أخرى : التخزين المؤقت (الذاكرة أو Redis — تخزين النتائج المكلفة لعدم إعادتها، وهو غالبا الأعلى أثرا)، وتحسين استعلامات القاعدة (الفهرسة، وتجنب مشكلة N+1 — فالقاعدة هي غالبا الاختناق الحقيقي)، وعدم حجب حلقة الأحداث (لا عمليات متزامنة ثقيلة على الخيط الرئيسي)، والتوازي (Promise.all للعمليات المستقلة)، والتوسع الأفقي (عدة نسخ خلف موزّع حمل (load balancer) — ومن هنا فائدة التطبيقات عديمة الحالة ورموز JWT). يخزّن ساليم الفهرس مؤقتا : فالطلبات المتكررة لم تعد تمس القاعدة.
ترتيب المردودية النموذجي : قاعدة البيانات (الفهرس، N+1)، ثم التخزين المؤقت، ثم العنقدة، ثم التوسع الأفقي — موجَّها دائما بالقياس.
3. المنهجية الجيدة : قس، استهدف، تحقق
المبدأ الأساسي : لا تحسين مبكر. اكتبوا شيفرة صحيحة وواضحة أولا، وقيسوا (التنميط، والمقاييس، وأزمنة الطلبات) لتحديد الاختناقات الحقيقية عندما تقع، وحسّنوا باستهداف حيث يهم، ثم أعيدوا القياس للتأكيد. التحسين على العمى يضيع الوقت ويعقّد الشيفرة ويخطئ المشكلة الحقيقية غالبا — فالحدس يخدع، والقياس يفصل. ينمّط ساليم قبل لمس الشيفرة : وكان الاختناق في القاعدة، لا في حلقاته.
يتفوق Node في الإدخال والإخراج (الخوادم، والواجهات، واللحظي) — وحدّ الأحادية يخص المعالج، لا الإدخال والإخراج، ومعظم تطبيقات الويب مقيدة بالإدخال والإخراج. ومستعمَلا جيدا، يخدم Node أحمالا كبيرة جدا.
🔎 مثال ملموس — ساليم يستغل النوى
العنقدة بـ PM2، ثم التخزين المؤقت.
# تشغيل نسخة لكل نواة
pm2 start app.js -i max
# القياس قبل التحسين (التنميط)
# التخزين المؤقت لنتيجة مكلفة (Redis)
# التحقق : لا شيء يحجب حلقة الأحداث
القراءة : كل سطر خطوة قابلة للاختبار على حدة.
الدرس : قاعدة البيانات غالبا الاختناق الحقيقي — فقيسوها أولا.
مفردات القسم
- العنقدة
- عدة نسخ من التطبيق (نسخة لكل نواة) تتقاسم الطلبات.
مثال بسيط: يشغّل ساليم واجهته مع PM2 في وضع العنقدة.
ما ليس كذلك: Node يستعمل كل النوى تلقائيا.
رد فعل: كم نواة نائمة على خادمي ؟
- خيوط العمال
- خيوط منفصلة للحسابات الثقيلة، دون حجب الحلقة.
مثال بسيط: يفوّض ساليم إليها تصديرا ضخما كان يجمّد الواجهة.
ما ليس كذلك: العنقدة نفسها.
رد فعل: هل يحجب هذا الحساب الخيط الرئيسي ؟
- التخزين المؤقت
- تخزين النتائج المكلفة لعدم إعادة حسابها.
مثال بسيط: فهرس ساليم يُقدَّم من التخزين، لا من القاعدة بعد.
ما ليس كذلك: إضافة خوادم قبل التخزين.
رد فعل: أي الطلبات تعود بلا انقطاع متماثلة ؟
- التنميط
- القياس لتحديد الاختناقات الحقيقية قبل التحسين.
مثال بسيط: يكتشف ساليم أن البطء من استعلام غير مفهرس.
ما ليس كذلك: تحسين حلقاته بالحدس.
رد فعل: هل قست قبل لمس الشيفرة ؟
- التوسع الأفقي
- عدة خوادم خلف موزع حمل.
مثال بسيط: يخطط ساليم لنسخ قابلة للنسخ بفضل تطبيقه عديم الحالة.
ما ليس كذلك: استغلال نوى آلة واحدة.
رد فعل: هل يُنسَخ تطبيقي بسهولة (عديم الحالة) ؟
في التطبيق — تحسين تطبيق وتوسيع نطاقه
- استعملوا العنقدة (وحدة cluster أو PM2) لتشغيل نسخة لكل نواة واستغلال المعالج كله (لكون Node أحادي الخيط).
- خزّنوا مؤقتا نتيجة مكلفة (استعلاما متكررا) — في الذاكرة أو مع Redis — وقيسوا المكسب.
- نمّطوا لتحديد الاختناقات الحقيقية قبل التحسين (القياس قبل التحسين) ؛ وتحققوا من أن لا شيء يحجب حلقة الأحداث.
- افهموا التوسع الأفقي : عدة نسخ خلف موزع حمل، وفائدة تطبيق « عديم الحالة » (JWT) لسهولة النسخ.
نص جاهز للقول — تبرير تحسين
« في الجزائر، تتباطأ واجهتنا ساعات الذروة. وقد قست : استعلامات الفهرس هي التي تشبع القاعدة. أقترح خطوتين مستهدفتين : العنقدة لاستغلال كل النوى، والتخزين المؤقت على الفهرس. نعيد القياس بعدها، ولا نضيف خوادم إلا إذا برر القياس ذلك. »
يُقال للمسؤول لاعتماد تحسين مقيس بدلا من إعادة كتابة على العمى.
نموذج للنسخ واللصق — بطاقة تشخيص الأداء
الأداء — تشخيص
العرَض : _______________ (متى ؟ ___)
القياس : زمن الاستجابة ___ · أبطأ استعلام ___
الاختناق المشتبه : قاعدة / غياب التخزين / حلقة محجوبة / معالج : ___
الإجراء المستهدَف : عنقدة / تخزين / فهرس / عامل : ___
إعادة القياس : قبل ___ ← بعد ___ · المكسب : ___
فردي / ميزانية صغيرة
ساليم وحده : PM2 في وضع العنقدة + تخزين مؤقت في الذاكرة يكفي لاستيعاب الذرى دون خادم جديد.
شركة صغيرة جدا / فريق مصغر
فهرسوا الاستعلامات البطيئة أولا : وهو غالبا المكسب الأسرع، دون بنية تحتية.
شركة صغيرة ومتوسطة في الجزائر
يخطط ساليم للقياسات ساعات الذروة في الجزائر، مع بروتوكول إعادة قياس بعد كل تغيير.
فريق يبدأ
ثنائي : أحدهما ينمّط بينما يجهّز الآخر التخزين المؤقت ؛ ومراجعة مشتركة للقياسات قبل أي تحسين.
✓ ممارسات جيدة
- استغلوا كل النوى بالعنقدة (PM2 في الإنتاج).
- خزّنوا النتائج المكلفة مؤقتا ؛ وحسّنوا استعلامات القاعدة (الفهرس، N+1).
- قيسوا (نمّطوا) قبل التحسين، واستهدفوا الاختناقات الحقيقية.
✗ أخطاء شائعة
- ترك عملية واحدة لا تستغل إلا نواة واحدة.
- التحسين المبكر (ضياع وقت، وتعقيد عديم الفائدة).
- حجب حلقة الأحداث بحساب ثقيل على المعالج في الخيط الرئيسي.
النقاط الأساسية
- لكون Node أحادي الخيط : العنقدة (clustering) (cluster / PM2) تشغّل نسخة لكل نواة لاستغلال كل النوى. وخيوط العمال للثقيل على المعالج.
- الروافع : التخزين المؤقت (Redis — غالبا الأعلى أثرا)، وتحسين الاستعلامات (الفهرسة، وتجنب N+1)، وعدم حجب الحلقة، والتوازي (Promise.all).
- القياس (التنميط) قبل التحسين (القاعدة الذهبية) ؛ وتحديد الاختناقات الحقيقية بدلا من التحسين على العمى.
- التوسع الأفقي : عدة خوادم خلف موزع حمل (load balancer) (يفضّل التطبيقات عديمة الحالة / JWT). ولا تحسين مبكر.
تحدي 48 ساعة — طبّق غدا
املؤوا بطاقة التشخيص لـ بطء حقيقي واحد في تطبيقكم : العرَض، والقياس، والاختناق المشتبه — دون لمس الشيفرة بعد.
- أستطيع شرح العنقدة مقابل خيوط العمال في جملة واحدة.
- بطاقة تشخيصي (القياس قبل التحسين) مملوءة.
- أعرف لماذا القاعدة هي المشتبه الأول.
أسئلة شائعة
لماذا العنقدة ضرورية، وهل Node خيار سيئ للأداء ؟
العنقدة ضرورية لأن Node ينفذ شيفرتكم على خيط واحد (نواة واحدة)، بينما الخوادم الحديثة فيها عدة نوى : فعملية واحدة تهدر النوى الأخرى. والعنقدة (وحدة cluster، أو PM2 الذي يؤتمتها مع إعادة تشغيل تلقائية ومراقبة) تشغّل عدة عمليات تتقاسم الطلبات. لكن ذلك لا يجعل Node خيارا سيئا : فـ Node يتفوق في الإدخال والإخراج (الخوادم، والواجهات، واللحظي — أغلب تطبيقات الويب) بنموذجه غير الحاجب، وحدّ الأحادية يخص المعالج (يُدار عبر خيوط العمال)، و Node يتوسع جيدا (عمودي + أفقي). ومستعمَلا جيدا، يخدم Node أحمالا كبيرة جدا.
كيف أعرف متى وماذا أحسّن دون الوقوع في التحسين المبكر ؟
القاعدة الذهبية : لا تحسّنوا قبل مشكلة حقيقية ومقيسة. فالتحسين المبكر يضيع الوقت ويعقّد الشيفرة ويخطئ الاختناق الحقيقي (الحدس يخدع). المنهجية : شيفرة صحيحة وواضحة أولا، والقياس (التنميط، والمقاييس) عندما تقع مشكلة، وتحسين مستهدَف حيث يهم، وإعادة القياس للتأكيد. الروافع الشائعة : قاعدة البيانات (الفهرس، N+1)، والتخزين المؤقت (Redis)، والعنقدة، وحلقة غير محجوبة، والتوازي، والتوسع الأفقي.
كيف يستغل تطبيق Node كل نوى خادم ؟