موقعنا كان ينهار في أوقات الذروة: كيف أنقذني اختبار الإجهاد (Stress Testing) من جحيم الأعطال المفاجئة؟

ليلة إطلاق المنتج الجديد: “أبو عمر، الموقع وقع!”

كنت قاعد في أمان الله، بشرب كاسة الشاي بالنعناع بعد يوم شغل طويل، ومبسوط إنه أطلقنا الموسم الجديد لمتجر إلكتروني لأحد العملاء. كان الإطلاق متزامن مع حملة إعلانية كبيرة، والتوقعات كانت عالية. فجأة، برن التلفون… رقم مدير المشروع. قلبي نقزني.

“أبو عمر، شو هالحكي يا زلمة! الموقع وقع! الناس مش قادرة تفوت، والطلبات واقفة!”. نزلت عليّ الجملة زي الصاعقة. فتحت اللابتوب بسرعة، وإيدي بترجف. شفت بعيني رسالة الخطأ “503 Service Unavailable” تملأ الشاشة. حاولنا نعمل إعادة تشغيل للسيرفرات، واشتغل الموقع لدقائق… ثم انهار مرة أخرى.

قضينا الليلة كلها في حالة طوارئ، نحاول إطفاء الحرائق بينما رسائل العملاء الغاضبة تتراكم. كانت تجربة مُهينة ومُحبطة بكل معنى الكلمة. خسرنا مبيعات، وخسرنا ثقة، والأهم، خسرنا راحة بالنا. في تلك الليلة، أقسمت أن هذا الكابوس لن يتكرر. ومن هنا، بدأت رحلتي الحقيقية مع عالم اختبارات الأداء، وتحديداً، “اختبار الإجهاد” أو الـ Stress Testing.

ما هو اختبار الإجهاد (Stress Testing)؟ وليش هو طوق النجاة؟

ببساطة شديدة، تخيل إنك بتبني جسر. هل بتفتتحه للسيارات مباشرة؟ طبعاً لأ. أول إشي بتجيب أوزان ثقيلة، شاحنات محملة، وبتحطها فوق الجسر. بتزيد الوزن شوي شوي… كمان… وكمان… لحد ما تشوف وين أول نقطة ضعف رح تظهر. هل رح يميل؟ هل رح يظهر شرخ؟ هذا هو بالضبط اختبار الإجهاد.

في عالم البرمجيات، اختبار الإجهاد هو عملية دفع نظامك (موقعك، تطبيقك، واجهتك البرمجية API) إلى أقصى حدوده، وحتى أبعد من حدوده، لنرى كيف سيتصرف. الهدف مش بس نعرف “كم مستخدم بيتحمل”، الهدف الأهم هو نعرف “كيف ينهار؟” و “أين ينهار؟”.

الفرق بين اختبار الحمل (Load Testing) واختبار الإجهاد (Stress Testing):
اختبار الحمل (Load Test): يتأكد أن النظام يعمل بشكل جيد تحت الحمل المتوقع (مثلاً 1000 مستخدم متزامن).
اختبار الإجهاد (Stress Test): يزيد الحمل بشكل مستمر فوق المتوقع ليعرف نقطة الانهيار القصوى (مثلاً يبدأ بـ 1000 ويزيد حتى ينهار النظام عند 2500 مستخدم).

التشخيص: لماذا كان موقعنا ينهار؟

بعد ليلة الكارثة، قررنا نعمل تشريح كامل للمشكلة. ما بدنا حلول مؤقتة، بدنا نعرف السبب الجذري. الشكوك كانت تدور حول عدة متهمين كالعادة:

  • قاعدة البيانات (Database): هل هناك استعلامات (Queries) بطيئة تستهلك كل الموارد؟
  • الخادم (Server): هل المعالج (CPU) أو الذاكرة (RAM) تصل إلى 100% وتختنق؟
  • الكود نفسه (Application Code): هل هناك تسريب في الذاكرة (Memory Leak) أو خوارزميات غير فعالة؟
  • خدمات الطرف الثالث (Third-party APIs): هل واجهة برمجية خارجية نعتمد عليها لا تستجيب تحت الضغط؟

بدون بيانات حقيقية، كل هذا مجرد تخمين. وهنا جاء دور بطل قصتنا: اختبار الإجهاد.

كيف طبقنا اختبار الإجهاد خطوة بخطوة (الدليل العملي)

قررنا نستخدم أداة اسمها K6 (من Grafana Labs). ليش K6 بالذات؟ لأنها حديثة، سهلة، وبتستخدم لغة JavaScript لكتابة الاختبارات، وهي لغة مألوفة لأغلب مطوري الويب.

الخطوة الأولى: كتابة سيناريو الاختبار

أول شيء، لازم نكتب “سيناريو” يحاكي سلوك المستخدم الحقيقي. المستخدم ما بزور الصفحة الرئيسية وبس، هو بتصفح المنتجات، بضيف للسلة، وبروح لصفحة الدفع.

هذا مثال بسيط لسكريبت K6 كتبناه لمحاكاة هذا السلوك:


import http from 'k6/http';
import { sleep, check } from 'k6';

// 1. خيارات الاختبار: هنا نحدد عدد المستخدمين الافتراضيين ومدة الاختبار
export const options = {
  stages: [
    { duration: '2m', target: 200 }, // زيادة تدريجية إلى 200 مستخدم خلال دقيقتين
    { duration: '5m', target: 200 }, // البقاء عند 200 مستخدم لمدة 5 دقائق
    { duration: '2m', target: 1000 }, // محاكاة وقت الذروة المفاجئ: زيادة إلى 1000 مستخدم خلال دقيقتين (Spike)
    { duration: '3m', target: 1000 }, // البقاء عند 1000 مستخدم
    { duration: '1m', target: 0 },    // تقليل الحمل للصفر
  ],
  thresholds: {
    'http_req_failed': ['rate<0.01'],   // نسبة الطلبات الفاشلة يجب أن تكون أقل من 1%
    'http_req_duration': ['p(95)<800'], // 95% من الطلبات يجب أن تتم في أقل من 800ms
  },
};

// 2. السيناريو الرئيسي الذي سينفذه كل مستخدم افتراضي
export default function () {
  // زيارة الصفحة الرئيسية
  const res1 = http.get('https://my-test-site.com/');
  check(res1, { 'Homepage was 200': (r) => r.status === 200 });
  sleep(1);

  // البحث عن منتج
  const res2 = http.get('https://my-test-site.com/api/products?search=my-product');
  check(res2, { 'Search API was 200': (r) => r.status === 200 });
  sleep(1);

  // إضافة المنتج للسلة
  const payload = JSON.stringify({ productId: '12345', quantity: 1 });
  const params = { headers: { 'Content-Type': 'application/json' } };
  const res3 = http.post('https://my-test-site.com/api/cart', payload, params);
  check(res3, { 'Add to cart was 200': (r) => r.status === 200 });
  sleep(2);
}

هذا السكريبت يحاكي زيادة تدريجية في عدد المستخدمين، ثم فترة ثبات، ثم “قفزة” مفاجئة في الحمل، وهذا بالضبط ما يحدث في الحملات الإعلانية.

الخطوة الثانية: تشغيل الاختبار ومراقبة النتائج

قمنا بإنشاء بيئة اختبار (Staging Environment) مطابقة تماماً لبيئة الإنتاج. (نصيحة ذهبية: إياك أن تجري اختبار إجهاد على بيئة الإنتاج الحية إلا إذا كنت تعرف تماماً ماذا تفعل!).

شغلنا الاختبار من خلال سطر الأوامر:


k6 run stress-test.js

وبدأنا نراقب لوحة التحكم (Dashboard) الخاصة بالسيرفرات وقاعدة البيانات. في البداية، كل شيء كان تمام. لكن عندما وصل عدد المستخدمين الافتراضيين (VUs) إلى حوالي 450، بدأت الكارثة تتكرر أمام أعيننا، ولكن هذه المرة في بيئة آمنة:

  • زمن الاستجابة (Request Duration): قفز من 200ms إلى 5000ms وأكثر.
  • معدل الأخطاء (Failed Requests): بدأ بالارتفاع بشكل مخيف.
  • استهلاك المعالج (CPU Usage): وصل إلى 100% على سيرفر قاعدة البيانات.

وجدنا الجاني! المشكلة كانت في قاعدة البيانات.

الخطوة الثالثة: الإصلاح وإعادة الاختبار

بعد تحديد المشكلة، أصبح الحل أسهل. وجدنا أن هناك استعلاماً معيناً (SQL Query) في صفحة المنتجات كان يقوم بعملية فحص كامل للجدول (Full Table Scan) في كل مرة يتم طلبه، وبدون استخدام الفهارس (Indexes).

الإصلاح الأول: تحسين قاعدة البيانات (Database Optimization)
قمنا بإضافة الفهرس المناسب للجدول. الفرق كان كالليل والنهار.

الإصلاح الثاني: التخزين المؤقت (Caching)
أضفنا طبقة تخزين مؤقت (Caching Layer) باستخدام Redis للبيانات التي لا تتغير كثيراً، مثل قائمة المنتجات الأكثر مبيعاً في الصفحة الرئيسية. هذا قلل الضغط على قاعدة البيانات بشكل هائل.

الإصلاح الثالث: التوسع الأفقي (Horizontal Scaling)
أدركنا أن خادماً واحداً لن يكون كافياً أبداً. قمنا بضبط البنية التحتية لاستخدام موازن أحمال (Load Balancer) مع مجموعة من الخوادم التي يمكن زيادتها تلقائياً (Auto-scaling Group) عند زيادة الضغط.

بعد كل إصلاح، كنا نعيد تشغيل اختبار الإجهاد لنرى التحسن. استمرت هذه الدورة (اختبار -> اكتشاف -> إصلاح -> إعادة اختبار) حتى أصبح النظام قادراً على تحمل 2000 مستخدم متزامن بكل أريحية وبدون أي أخطاء.

نصائح من قلب الميدان (من خبرة أبو عمر)

  • لا تنتظر الكارثة: اجعل اختبارات الأداء جزءاً أساسياً من دورة حياة التطوير (CI/CD pipeline)، وليس شيئاً تفعله فقط عند حدوث مشكلة.
  • ابدأ صغيراً: لا تحاول محاكاة مليون مستخدم من أول مرة. ابدأ بحمل صغير، وافهم النتائج، ثم زد الحمل تدريجياً.
  • راقب كل شيء: اختبار الأداء بدون مراقبة (Monitoring) للخوادم وقواعد البيانات والتطبيق هو نصف العمل. استخدم أدوات مثل Prometheus, Grafana, Datadog لترى الصورة كاملة.
  • المشكلة ليست دائماً في الكود: يا جماعة، تذكروا أن عنق الزجاجة (Bottleneck) يمكن أن يكون في الشبكة، أو إعدادات قاعدة البيانات، أو نظام التشغيل، وليس فقط في الكود الذي كتبته.

الخلاصة: نام مرتاح البال 😉

تجربة انهيار الموقع كانت قاسية، لكنها علمتنا درساً لن ننساه. اختبار الإجهاد ليس مجرد أداة تقنية، بل هو تغيير في العقلية. هو الانتقال من مطور “متفاعل” يركض لإصلاح الأعطال، إلى مهندس “استباقي” يبني أنظمة قوية وقادرة على الصمود.

في الإطلاق التالي، كنت أشرب الشاي بالنعناع وأنا أراقب لوحة التحكم بهدوء وثقة. كان الموقع يعمل كالساعة تحت ضغط آلاف المستخدمين. تلك الليلة، نمت مرتاح البال.

نصيحتي الأخيرة لك: من الأفضل أن تكسر موقعك بنفسك في بيئة آمنة ومُتحكّم بها، على أن يكسره لك المستخدمون في أسوأ وقت ممكن.

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

أتمتة العمليات

إشعاراتنا كانت ضجيجاً والمهام تتطلب التنقل بين ألف شاشة: كيف أنقذنا ChatOps من جحيم الفوضى التشغيلية؟

أشارككم تجربتي كـ"أبو عمر"، مبرمج فلسطيني، في تحويل فوضى الإشعارات والتنقل بين الأنظمة إلى بيئة عمل منظمة وفعالة باستخدام ChatOps. اكتشفوا كيف أتمتنا عملياتنا، ووفرنا...

12 أبريل، 2026 قراءة المزيد
نصائح برمجية

شروطنا المتشعبة كانت متاهة: كيف أنقذتنا ‘شروط الحماية’ (Guard Clauses) من جحيم الـ if-else المتداخل؟

هل تعاني من تداخل الشروط في الكود؟ أشاركك قصة حقيقية وكيف غيّرت 'شروط الحماية' (Guard Clauses) طريقة كتابتي للكود، محولةً المتاهات المعقدة إلى مسارات واضحة...

12 أبريل، 2026 قراءة المزيد
​معمارية البرمجيات

خدماتنا كانت متشابكة كخيوط العنكبوت: كيف أنقذتنا ‘المعمارية الموجهة بالأحداث’ (EDA) من جحيم الاعتمادية المباشرة؟

أشارككم قصة حقيقية من تجربتي كـ "أبو عمر" المبرمج، وكيف كانت خدماتنا على وشك الانهيار بسبب التشابك والاعتمادية. اكتشفوا معنا كيف كانت "المعمارية الموجهة بالأحداث"...

12 أبريل، 2026 قراءة المزيد
ذكاء اصطناعي

قرارات نموذجنا كانت صندوقاً أسود: كيف أنقذتنا تقنيات التفسير (XAI) من جحيم التنبؤات الغامضة؟

أشارككم قصة من الميدان، يوم كاد نموذج ذكاء اصطناعي "صندوق أسود" أن يورطنا في قرارات كارثية. هذه المقالة هي دليلك لفهم تقنيات الذكاء الاصطناعي القابل...

12 أبريل، 2026 قراءة المزيد
خوارزميات

قاعدة بياناتنا كانت تستغيث: كيف أنقذنا ‘فلتر بلوم’ من جحيم التحقق المكلف من وجود العناصر؟

أشارككم قصة حقيقية من ميدان المعركة البرمجية، يوم كادت قاعدة بياناتنا أن تنهار تحت ضغط عمليات التحقق المتكررة. سأكشف لكم عن السلاح السري الذي أنقذنا،...

12 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

تطبيقنا كان حصناً منيعاً: كيف أنقذتنا ‘معايير الوصول الرقمي (WCAG)’ من جحيم الإقصاء الرقمي؟

أشارككم قصة حقيقية حول كيف أدركنا أن تطبيقنا "المثالي" كان يقصي شريحة كبيرة من المستخدمين. هذه المقالة هي رحلتنا في فهم وتطبيق معايير الوصول الرقمي...

11 أبريل، 2026 قراءة المزيد
البودكاست