كان إطلاقنا للميزات مقامرة: كيف أنقذنا اختبار التحميل (Load Testing) باستخدام k6 من جحيم انهيار الخوادم؟

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

لكن كان هناك شعور يراودني، “إحساس مش مريح” كما نقول بلهجتنا. الميزة تعمل بشكل رائع على أجهزتنا وفي بيئة الاختبار مع عدد قليل من المستخدمين. لكن ماذا سيحدث عندما يتدفق عليها آلاف المستخدمين في نفس اللحظة؟ التفتُ إلى مدير المشروع وقلت له: “يا جماعة، قبل ما نكبس الزر، لازم نعمل اختبار تحميل. القصة مش لعبة”.

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

ما هو اختبار التحميل (Load Testing) ولماذا هو شريان الحياة لتطبيقاتك؟

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

لماذا هو مهم لهذه الدرجة؟

  • تجربة المستخدم: لا أحد يحب موقعاً بطيئاً أو تطبيقاً يتوقف عن الاستجابة. صفحة تستغرق 3 ثوانٍ للتحميل تفقد أكثر من نصف زوارها المحتملين.
  • السمعة والثقة: انهيار نظامك في أوقات الذروة (مثل يوم إطلاق أو خلال حملة تسويقية) يدمر ثقة المستخدمين بعلامتك التجارية.
  • تحديد عنق الزجاجة (Bottlenecks): يكشف اختبار التحميل عن نقاط الضعف الخفية في نظامك. قد تكون المشكلة في قاعدة البيانات، أو استدعاء API خارجي، أو حتى في قطعة كود غير محسّنة لا تظهر مشكلتها إلا تحت الضغط.
  • توفير التكاليف: اكتشاف المشاكل وإصلاحها قبل الإطلاق أرخص بكثير من إصلاحها بعد أن تسبب الكارثة في بيئة الإنتاج.

نصيحة من أبو عمر: لا تنظر لاختبارات الأداء على أنها خطوة إضافية أو رفاهية. هي جزء لا يتجزأ من دورة حياة تطوير البرمجيات (SDLC)، تماماً مثل كتابة الكود نفسه.

لماذا اخترنا k6؟ رحلة البحث عن الأداة المثالية

في عالم اختبارات الأداء، هناك العديد من الأدوات العريقة مثل Apache JMeter و Gatling. لكننا اخترنا k6 لعدة أسباب جعلته مثالياً لفريقنا الحديث الذي يتبنى ثقافة الـ DevOps:

1. سهولة الاستخدام والكتابة (Developer-Friendly)

السكربتات في k6 تُكتب بلغة JavaScript (ES6)، وهي لغة يعرفها ويحبها معظم مطوري الويب. هذا يعني أن المطورين أنفسهم يمكنهم كتابة وصيانة اختبارات الأداء بسهولة، دون الحاجة لتعلم لغة جديدة أو التعامل مع واجهات رسومية معقدة كما في JMeter. هذا يزيل الحاجز بين المطورين ومهندسي الجودة.

2. الأداء العالي

أداة k6 مكتوبة بلغة Go، وهي لغة معروفة بأدائها العالي وقدرتها على التعامل مع المهام المتزامنة (Concurrency) بكفاءة. هذا يعني أن k6 نفسها تستهلك موارد قليلة جداً من الجهاز الذي تعمل عليه، مما يسمح لك بمحاكاة آلاف المستخدمين الافتراضيين (VUs) من جهاز واحد.

3. موجهة بالأهداف (Goal-Oriented)

أجمل ما في k6 هو مفهوم الشروط (Thresholds). يمكنك تحديد معايير نجاح واضحة للاختبار. على سبيل المثال: “يجب أن يفشل هذا الاختبار إذا كانت نسبة الأخطاء أعلى من 1%، أو إذا كان 95% من الطلبات يستغرق أكثر من 500 ملي ثانية”. هذا يجعل دمجها في أنظمة التكامل المستمر (CI/CD) أمراً سهلاً وفعالاً.

لنبدأ العمل: أول اختبار تحميل لك مع k6 (خطوة بخطوة)

دعونا نتوقف عن الكلام النظري وننتقل للتطبيق العملي. سأريكم كيف يمكنكم كتابة وتشغيل أول اختبار تحميل لكم في دقائق.

التحضير: تنصيب k6 وكتابة أول سكربت

أولاً، تحتاج إلى تنصيب k6. العملية بسيطة جداً وتجدون تفاصيلها على موقعهم الرسمي لمختلف أنظمة التشغيل (Windows, macOS, Linux).

بعد التنصيب، قم بإنشاء ملف جديد باسم script.js واكتب فيه الكود التالي:


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

// هذا هو الجزء الذي يتم إعداده مرة واحدة في البداية
export const options = {
  // محاكاة 10 مستخدمين افتراضيين (VUs)
  vus: 10,
  // لمدة 30 ثانية
  duration: '30s',
};

// هذه هي الدالة الرئيسية التي سينفذها كل مستخدم افتراضي بشكل متكرر
export default function () {
  // إرسال طلب GET إلى واجهة برمجة تطبيقات اختبارية
  http.get('https://test-api.k6.io/public/crocodiles/1/');
  
  // انتظار لمدة ثانية واحدة قبل تكرار الطلب (لمحاكاة سلوك المستخدم)
  sleep(1);
}

لتشغيل هذا الاختبار، افتح الطرفية (Terminal) في نفس المجلد واكتب الأمر:

k6 run script.js

ستبدأ k6 في العمل وسترى ملخصاً رائعاً للنتائج في النهاية، يوضح لك عدد الطلبات، ومعدل الطلبات في الثانية، ومتوسط مدة الاستجابة، وأي أخطاء حدثت.

محاكاة الواقع: تصميم سيناريو اختبار حقيقي

الاختبار السابق بسيط جداً. في الواقع، لا يأتي المستخدمون جميعهم دفعة واحدة. يتزايد عددهم تدريجياً. يمكننا محاكاة ذلك باستخدام المراحل (Stages):


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

export const options = {
  stages: [
    // 1. زيادة تدريجية من 0 إلى 100 مستخدم خلال 30 ثانية
    { duration: '30s', target: 100 }, 
    // 2. البقاء على 100 مستخدم لمدة دقيقة واحدة (هذا هو اختبار التحميل الفعلي)
    { duration: '1m', target: 100 }, 
    // 3. تقليل تدريجي إلى 0 مستخدم خلال 30 ثانية
    { duration: '30s', target: 0 },   
  ],
};

export default function () {
  http.get('https://test-api.k6.io/public/crocodiles/1/');
  sleep(1);
}

هذا السيناريو أقرب بكثير للواقع، حيث يسمح للنظام “بالإحماء” ثم يضعه تحت ضغط ثابت، ثم يراقبه وهو “يبرد”.

التحقق من الصحة: استخدام Checks و Thresholds

هنا تكمن قوة k6 الحقيقية. كيف نعرف إذا كان أداء النظام جيداً أم لا؟

  • Checks: هي تأكيدات بسيطة داخل الكود لا توقف الاختبار، لكن يتم حسابها في النتائج. تشبه `assert` في اختبارات الوحدات.
  • Thresholds: هي شروط النجاح/الفشل للاختبار بأكمله. إذا لم يتم استيفاء هذه الشروط، فإن k6 ستخرج برمز خطأ (non-zero exit code)، وهو أمر مثالي لخطوط أنابيب CI/CD.

لنعدّل على السكربت السابق لإضافة هذه المفاهيم:


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

export const options = {
  stages: [
    { duration: '30s', target: 100 },
    { duration: '1m', target: 100 },
    { duration: '30s', target: 0 },
  ],
  // هنا نحدد شروط النجاح (Thresholds)
  thresholds: {
    // 95% من الطلبات يجب أن تكتمل في أقل من 200 ملي ثانية
    'http_req_duration': ['p(95)<200'], 
    // يجب أن تكون نسبة الطلبات الناجحة (status 200) أكثر من 99%
    'checks{status_is_200}': ['rate>0.99'],
  },
};

export default function () {
  const res = http.get('https://test-api.k6.io/public/crocodiles/1/');
  
  // هنا نستخدم (Check) للتحقق من حالة الاستجابة
  check(res, {
    'status is 200': (r) => r.status === 200,
  });

  sleep(1);
}

القصة تتواصل: كيف كشف k6 عن “عنق الزجاجة” في نظامنا؟

بالعودة إلى قصتنا، قمت بكتابة سكربت مشابه لما سبق، لكنه يحاكي السيناريو الحقيقي لاستخدام ميزة “التوصيات الذكية”. بدأت الاختبار بـ 500 مستخدم افتراضي يتزايدون تدريجياً.

في الدقائق الأولى، كانت الأمور تبدو جيدة. لكن عندما وصل عدد المستخدمين إلى حوالي 300، بدأت أرى أرقاماً مقلقة في مخرجات k6:

  • http_req_duration: متوسط مدة الاستجابة قفز من 150ms إلى 2500ms (2.5 ثانية)!
  • http_req_failed: بدأت نسبة الطلبات الفاشلة في الارتفاع بسرعة.
  • checks: نسبة التحقق من `status is 200` انخفضت إلى أقل من 60%.

كانت هذه هي الإشارة الحمراء. النظام كان ينهار. أوقفنا الاختبار وبدأنا التحليل. بمساعدة أدوات مراقبة الخوادم (Monitoring)، وجدنا أن استعلاماً معيناً في قاعدة البيانات (Database Query) كان السبب. هذا الاستعلام كان يعمل بشكل جيد مع مستخدم واحد، لكن مع 300 مستخدم متزامن، كان يقوم بقفل (lock) جداول معينة ويجعل بقية الطلبات تنتظر، مما أدى إلى تأثير كرة الثلج الذي كاد أن يطيح بالخادم بأكمله.

أمضينا الساعات القليلة التالية في تحسين هذا الاستعلام وإضافة بعض الفهارس (Indexes) الضرورية لقاعدة البيانات، ثم أعدنا تشغيل اختبار التحميل. النتيجة؟ كانت مذهلة. صمد النظام بسهولة تحت ضغط 1000 مستخدم افتراضي، مع بقاء مدة الاستجابة تحت 200ms ونسبة أخطاء تقارب الصفر.

نصائح من “أبو عمر”: حيل وأفضل الممارسات في اختبارات التحميل

من خلال سنوات من العمل في هذا المجال، تعلمت بعض الدروس التي أود مشاركتها معكم:

  1. ابدأ صغيراً ثم توسع: لا تبدأ باختبار يحاكي مليون مستخدم. ابدأ بسيناريو بسيط، تأكد من أنه يعمل، ثم قم بزيادة التعقيد والحمل تدريجياً.
  2. اختبر على بيئة تشبه الإنتاج: أفضل النتائج تأتي من الاختبار على بيئة (Staging Environment) تكون مواصفاتها مطابقة لبيئة الإنتاج (Production). الاختبار على جهازك المحلي يعطيك فكرة، لكنه ليس مقياساً حقيقياً.
  3. لا تنسَ “وقت التفكير”: المستخدمون الحقيقيون لا يضغطون على الأزرار بشكل مستمر. أضف دائماً sleep() بين طلباتك لمحاكاة “وقت التفكير” أو الوقت الذي يقضيه المستخدم في قراءة الصفحة.
  4. أتمتة، ثم أتمتة، ثم أتمتة: ادمج اختبارات k6 في خط أنابيب CI/CD الخاص بك (مثل Jenkins, GitLab CI, GitHub Actions). اجعلها تعمل تلقائياً مع كل عملية دمج للكود. هذا يحول اختبار الأداء من حدث لمرة واحدة إلى عملية مستمرة.
  5. حلل النتائج بذكاء: الأرقام وحدها لا تكفي. اربط نتائج k6 ببيانات من أدوات المراقبة الأخرى (مثل Prometheus, Grafana, Datadog) للحصول على صورة كاملة لما يحدث داخل نظامك أثناء الاختبار.

الخلاصة: لا تترك نجاحك للصدفة 🎲

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

تذكر دائماً، في عالم البرمجيات، الأمل ليس استراتيجية. بناء منتج رائع شيء، والتأكد من أنه يستطيع تحمل نجاحه شيء آخر تماماً. اختبارات التحميل باستخدام أدوات مثل k6 ليست ترفاً، بل هي بوليصة تأمين ضد الكوارث، واستثمار مباشر في استقرار منتجك وراحة بالك. فاستثمر فيها اليوم، لتنم قرير العين في ليلة الإطلاق. 😉

أبو عمر

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

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

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

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

آخر المدونات

البنية التحتية وإدارة السيرفرات

من العمى التشغيلي إلى البصيرة الكاملة: رحلتي مع Prometheus و Grafana لإنقاذ أنظمتنا

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

5 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

من شلل الخوف إلى إبداع الفريق: كيف أنقذنا مفهوم ‘الأمان النفسي’ من جحيم الصمت القاتل؟

مقالة من قلب التجربة عن كيفية تحويل فريق يخشى ارتكاب الأخطاء إلى بيئة عمل آمنة ومبدعة. أشارككم قصة حقيقية وخطوات عملية أنقذت فريقنا من "الصمت...

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

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

أشارككم قصة من قلب المعركة البرمجية، كيف كاد مشروعنا أن ينهار بسبب قرار قديم لم يتذكره أحد. وكيف أصبحت "سجلات القرارات المعمارية" (ADRs) هي ذاكرتنا...

5 مايو، 2026 قراءة المزيد
تسويق رقمي

كانت ميزانيتنا التسويقية تحترق: كيف أنقذتنا ‘نماذج الإحالة’ من جحيم تخمين العائد على الاستثمار؟

أتذكر جيداً تلك الاجتماعات المحمومة، حيث كانت الأرقام تتراقص على الشاشة والميزانية التسويقية تتآكل دون أن نعرف أين يذهب كل دولار. في هذه المقالة، أشارككم...

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