wrk: كيفية اختبار تحميل API من سطر الأوامر
DEV Community

wrk: كيفية اختبار تحميل API من سطر الأوامر

ما هو wrk ومتى تستخدمه

wrk أداة اختبار أداء HTTP حديثة. تعمل من جهاز واحد متعدد الأنوية، وتستخدم الخيوط المتعددة مع حلقة أحداث قابلة للتوسع مثل epoll على Linux و kqueue على macOS. النتيجة: يمكنك توليد حمل كبير بدون إعداد أسطول من أجهزة الاختبار.

استخدم wrk عندما تريد إجابات مباشرة عن أسئلة مثل:

  • كم طلبًا في الثانية تتحمل نقطة النهاية؟
  • كيف يبدو زمن الاستجابة عند المتوسط، وخصوصًا عند الذيل مثل p99؟
  • هل يبقى الأداء ثابتًا بعد 30 ثانية أو دقيقتين من الحمل؟
  • هل المشكلة في الخادم أم في عرض النطاق أو قاعدة البيانات؟

لكن انتبه: wrk أداة قياس أداء، وليست أداة تحقق وظيفي. هي لا تتحقق من صحة JSON، ولا تتأكد من أن رمز الحالة 200، ولا تختبر عقد API. إذا أردت خلفية أوسع، راجع دليل اختبار تحميل API.

تثبيت wrk

macOS

أسهل طريقة هي Homebrew:

brew install wrk

على Apple Silicon، هذا الخيار مفضل لأن البناء من المصدر قد يواجه مشاكل متعلقة بـ LuaJIT وARM64.

لينكس: البناء من المصدر

ثبّت الأدوات المطلوبة أولًا:

sudo apt-get install build-essential libssl-dev git -y

ثم ابنِ الأداة:

git clone https://github.com/wg/wrk.git
cd wrk
make

بعدها انسخ الملف التنفيذي إلى مسار عام:

sudo cp wrk /usr/local/bin

وتأكد من التثبيت:

wrk --version

تشغيل أول اختبار

الصيغة الأساسية:

wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html

المعاني العملية للخيارات:

  • -t أو --threads: عدد خيوط التشغيل التي يستخدمها wrk. ابدأ غالبًا بخيط لكل نواة CPU.
  • -c أو --connections: عدد اتصالات HTTP المفتوحة، أي مستوى التزامن الذي تريد محاكاته.
  • -d أو --duration: مدة الاختبار مثل 30s أو 2m أو 2h.

مثال عملي أكثر لنقطة API محلية:

wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users

استخدم --latency في معظم الاختبارات لأنه يعرض نسب زمن الاستجابة مثل p50 و p90 و p99.

يمكنك أيضًا تحديد مهلة للطلبات:

wrk -t8 -c200 -d30s --latency --timeout 2s http://localhost:3000/api/users

هذا يجعل أي طلب لا يكتمل خلال ثانيتين يُسجل كمهلة، بدلًا من أن يشوه نتائج زمن الاستجابة.

قراءة مخرجات wrk

مثال مخرجات:

Running 5s test @ http://10.135.232.163:3000
  2 threads and 5 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.82ms    2.64ms   26.68ms   85.81%
    Req/Sec   550.90    202.40     0.98k    68.00%
  5494 requests in 5.01s, 1.05MB read
Requests/sec: 1096.54
Transfer/sec: 215.24KB

اقرأ التقرير بهذا الترتيب:

1. Requests/sec

Requests/sec: 1096.54 هذا هو رقم الإنتاجية الأساسي: كم طلبًا مكتملًا في الثانية. استخدمه للمقارنة بين:

  • إصدارين من الكود
  • إعدادين مختلفين للخادم
  • تشغيل قبل وبعد تحسين قاعدة البيانات
  • HTTP مقابل HTTPS

2. Transfer/sec

Transfer/sec: 215.24KB هذا يوضح حجم البيانات المنقولة في الثانية. يصبح مهمًا عندما تكون الاستجابات كبيرة أو عندما تشك أن الاختناق في الشبكة.

3. Latency

Latency     3.82ms    2.64ms   26.68ms

هنا المتوسط 3.82ms، لكن الحد الأقصى 26.68ms. إذا كان الحد الأقصى بعيدًا جدًا عن المتوسط، فهذا يعني أن بعض الطلبات تعاني من بطء واضح حتى لو كانت معظم الطلبات سريعة.

4. Latency Distribution

عند استخدام --latency سترى شيئًا مثل:

Latency Distribution
 50%   3.21ms
 75%   4.86ms
 90%   7.09ms
 99%  14.13ms

راقب 99% أو p99. المتوسط وحده قد يخفي مشكلات الذيل. إذا كان المتوسط 3ms لكن p99 هو 200ms، فالمستخدمون سيشعرون بالتذبذب.

اختبار نقطة نهاية GET

ابدأ دائمًا بتشغيل بسيط لتثبيت خط الأساس:

wrk -t4 -c50 -d30s --latency http://localhost:3000/api/health

ثم ارفع التزامن تدريجيًا:

wrk -t4 -c100 -d30s --latency http://localhost:3000/api/health
wrk -t4 -c200 -d30s --latency http://localhost:3000/api/health
wrk -t4 -c400 -d30s --latency http://localhost:3000/api/health

راقب متى يحدث التالي:

  • Requests/sec يتوقف عن الزيادة
  • p99 يقفز فجأة
  • تظهر أخطاء أو مهلات
  • CPU أو الذاكرة أو قاعدة البيانات تصل إلى الحد الأقصى

هذه النقطة عادةً تكشف حد التحمل العملي لنقطة النهاية.

إرسال طلبات POST باستخدام Lua

افتراضيًا، يرسل wrk طلبات GET. لاختبار POST أو إرسال JSON أو ضبط رؤوس مخصصة، استخدم ملف Lua.

أنشئ ملفًا باسم post.lua:

wrk.method = "POST"
wrk.body = '{"name": "Ada", "role": "engineer"}'
wrk.headers["Content-Type"] = "application/json"

ثم شغّل الاختبار:

wrk -t4 -c100 -d30s -s post.lua --latency http://localhost:3000/api/users

إذا كانت نقطة النهاية تتطلب مصادقة:

wrk.method = "POST"
wrk.body = '{"name": "Ada", "role": "engineer"}'
wrk.headers["Content-Type"] = "application/json"
wrk.headers["Authorization"] = "Bearer TOKEN123"

ثم:

wrk -t4 -c100 -d30s -s post.lua --latency http://localhost:3000/api/users

لطلبات form-urlencoded:

wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

إضافة رؤوس بدون Lua

للحالات البسيطة، استخدم -H مباشرة:

wrk -t4 -c100 -d30s \
  -H "Authorization: Bearer TOKEN123" \
  --latency \
  http://localhost:3000/api/protected

ولأكثر من رأس:

wrk -t4 -c100 -d30s \
  -H "Authorization: Bearer TOKEN123" \
  -H "Accept: application/json" \
  --latency \
  http://localhost:3000/api/protected

استخدم -H عندما تحتاج إلى رأس أو رأسين فقط. استخدم Lua عندما تحتاج إلى:

  • POST أو PUT أو PATCH
  • body مخصص
  • منطق لكل طلب
  • توليد بيانات ديناميكية

منهجية اختبار عملية

لا تبدأ مباشرة بـ -c1000. اتبع خطوات تصاعدية:

  1. اختبر نقطة صحة بسيطة

    wrk -t2 -c20 -d15s --latency http://localhost:3000/health
    

    هذا يؤكد أن أداة الاختبار والخادم يعملان.

  2. اختبر نقطة النهاية الحقيقية

    wrk -t4 -c100 -d30s --latency http://localhost:3000/api/users
    
  3. ارفع التزامن تدريجيًا

    wrk -t4 -c200 -d30s --latency http://localhost:3000/api/users
    wrk -t4 -c400 -d30s --latency http://localhost:3000/api/users
    wrk -t4 -c800 -d30s --latency http://localhost:3000/api/users
    
  4. قارن الأرقام
    أنشئ جدولًا بسيطًا:

    | الاتصالات | Requests/sec | p50 | p90 | p99 |
    |-----------|-------------|-----|-----|-----|
    | 100 | | | | |
    | 200 | | | | |
    | 400 | | | | |

    النقطة التي يبدأ عندها p99 بالقفز هي غالبًا أهم من أعلى رقم Requests/sec.

القيود: wrk لا يتحقق من صحة الاستجابة

هذه نقطة مهمة: wrk يخبرك أن الخادم رد بسرعة، لكنه لا يخبرك أن الرد صحيح. إذا كانت نقطة النهاية تُرجع HTTP 500 لكل طلب، قد تحصل على رقم Requests/sec مرتفع جدًا. السبب أن wrk يحسب تبادل HTTP مكتملًا، ولا يتحقق من:

  • رمز الحالة
  • بنية JSON
  • مخطط الاستجابة
  • منطق العمل
  • تحقق قاعدة البيانات أن العملية حدثت فعلًا

لذلك لا تعتمد على wrk وحده. استخدمه للإجابة عن سؤال: هل الأداء كافٍ تحت الحمل؟ ولا تستخدمه للإجابة عن سؤال: هل الـ API تعمل بشكل صحيح؟ لهذا تستخدم الفرق عادةً أداة أداء مثل wrk مع مجموعة اختبارات وظيفية.

أين يدخل Apidog في سير العمل

سير العمل العملي يتكون من طبقتين:

أولًا: تحقق من السلوك
قبل قياس الأداء، تأكد أن نقطة النهاية صحيحة. في Apidog يمكنك بناء سيناريوهات اختبار ترسل طلبات حقيقية وتتحقق من:

  • رموز الحالة
  • حقول JSON
  • مخطط الاستجابة
  • تسلسل الطلبات
  • تمرير البيانات بين الخطوات
  • التشغيل عبر بيئات مختلفة

هذه الطبقة تلتقط الأخطاء التي لا يراها wrk.

ثانيًا: قِس الأداء
بعد نجاح الاختبارات الوظيفية، شغّل wrk ضد نفس نقاط النهاية:

wrk -t8 -c300 -d60s --latency https://api.example.com/users

إذا أردت الاحتفاظ بالاختبارات الوظيفية واختبارات الأداء داخل منصة واحدة، يوفر Apidog أيضًا اختبار أداء مدمج. أما wrk فهو خيار ممتاز عندما تريد قياسات سريعة من سطر الأوامر.

تشغيل اختبارات Apidog في CI

الاختبار الوظيفي يجب أن يعمل في CI، وليس فقط محليًا. يمكن تشغيل Apidog بدون واجهة رسومية عبر CLI.

ثبّت الواجهة:

npm install -g apidog-cli

ثم شغّل سيناريو أو مجموعة محفوظة:

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,html,junit

شرح الخيارات:

  • -t: معرف السيناريو أو المجلد أو المجموعة
  • -e: معرف البيئة
  • -r: تنسيقات التقرير مثل cli و html و json و junit

للتشغيل المعتمد على بيانات متعددة:

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -d ./data.csv \
  -r cli,junit

استخدم إخراج junit لدمج النتائج مع أنظمة CI.

الفكرة العملية: شغّل Apidog في CI للتحقق من صحة السلوك. إذا نجح، شغّل wrk في بيئة اختبار أداء لقياس الإنتاجية. لا تقبل رقم أداء لنقطة نهاية فاشلة وظيفيًا.

لإعدادات قابلة للنسخ، راجع دليل CLI CI/CD أو دليل GitHub Actions. كما يغطي مرجع CLI الكامل بقية الخيارات.

الأسئلة الشائعة

ما الفرق بين wrk و ab؟

كلاهما يرسل حمل HTTP ويعرض الطلبات في الثانية. لكن wrk متعدد الخيوط ويستخدم حلقة أحداث، لذلك يتعامل مع التزامن العالي بشكل أفضل من ab، الذي يكون أبسط وأقل قدرة على توليد حمل كبير من جهاز واحد. لا يتحقق أي منهما من صحة الاستجابة.

كم عدد الخيوط والاتصالات التي أستخدمها؟

ابدأ بخيط لكل نواة CPU تقريبًا. إذا كان لديك 8 أنوية وتريد محاكاة 200 اتصال متزامن:

wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users

راقب جهاز توليد الحمل نفسه. إذا كان wrk يستهلك CPU بالكامل، فقد تكون تقيس حد جهاز الاختبار لا حد الخادم.

هل يدعم wrk HTTPS؟

نعم:

wrk -t4 -c100 -d30s --latency https://api.example.com/users

لكن TLS يضيف تكلفة CPU، لذلك قد ترى إنتاجية أقل من HTTP العادي.

هل يتحقق wrk من رمز الحالة؟

لا. wrk يقيس تبادلات HTTP المكتملة والتوقيت فقط. إذا كانت الاستجابة 500، سيستمر في عدّها ضمن النتائج. استخدم اختبارات وظيفية للتحقق من الصحة، ثم استخدم wrk للأداء.

كم يجب أن تستمر مدة الاختبار؟

للفحص السريع، 5 إلى 15 ثانية كافية. للأرقام الأكثر استقرارًا، استخدم 30 ثانية إلى عدة دقائق:

wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users

زد المدة إذا كنت تبحث عن مشاكل تظهر تحت حمل طويل، مثل تسرب الذاكرة أو تدهور الأداء بعد الإحماء.

ما الرقم الأهم: المتوسط أم p99؟

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

Comments

No comments yet. Start the discussion.