اختبار الأداء الدقيق باستخدام `wrk`

API7.ai

November 25, 2022

OpenResty (NGINX + Lua)

في هذه المقالة، سنتحدث عن اختبار الأداء. هذا الجزء ليس فريدًا لـ OpenResty بل ينطبق على خدمات الخلفية الأخرى.

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

إذن، كيف يتم إجراء اختبار الأداء العلمي والدقيق؟

أدوات اختبار الأداء

لإنجاز العمل بشكل جيد، يجب أولاً استخدام أداة جيدة. اختيار أداة اختبار أداء جيدة هو نصف النجاح.

أداة Apache Benchmark، المعروفة أيضًا باسم ab، والتي يجب أن تكون على دراية بها، هي بلا شك أسهل أداة لاختبار الأداء، ولكن للأسف، ليست مفيدة جدًا. هذا لأن جانب الخادم الحالي يتم تطويره بناءً على I/O متزامن وغير متزامن، وأداؤه ليس سيئًا. الأداة ab لا تستفيد من النوى المتعددة للجهاز والطلبات التي يتم إنشاؤها ليست تحت ضغط كافٍ. في هذه الحالة، النتائج التي يتم الحصول عليها من اختبار ab ليست حقيقية.

لذلك، يمكننا اختيار معيار لأداة اختبار الضغط: الأداة نفسها لديها أداء قوي ويمكنها توليد ضغط كافٍ لضغط برنامج جانب الخادم.

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

بالعودة إلى ممارسة OpenResty، فإن أداة اختبار الأداء التي نوصي بها هي wrk. أولاً، لماذا نختارها؟

أولاً، wrk تفي بمعايير اختيار الأداة. الضغط الذي تولده wrk على جهاز واحد يمكن أن يسمح لـ NGINX بسهولة بالوصول إلى 100% من استخدام وحدة المعالجة المركزية، ناهيك عن تطبيقات جانب الخادم الأخرى.

ثانيًا، wrk لديها الكثير من أوجه التشابه مع OpenResty. wrk ليس مشروعًا مفتوح المصدر تم كتابته من الصفر؛ بل يقف على أكتاف LuaJIT و Redis ويستفيد من موارد النوى المتعددة للنظام لتوليد الطلبات. بالإضافة إلى ذلك، تعرض wrk واجهة برمجة تطبيقات Lua تسمح لك بتضمين نصوص Lua الخاصة بك لتخصيص رؤوس الطلبات والمحتوى، مما يجعلها مرنة للغاية.

إذن، كيف يجب أن نستخدم wrk؟ الأمر بسيط مثل النظر إلى مقتطف الكود التالي.

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

هذا يعني أن wrk ستستخدم 12 خيطًا، وتحتفظ بـ 400 اتصال طويل لمدة 30 ثانية، لإرسال طلبات HTTP إلى واجهة API المحددة. بالطبع، إذا لم تحدد المعلمات، فإن wrk ستبدأ بخيطين وعشرة اتصالات طويلة بشكل افتراضي.

بيئة الاختبار

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

1. إيقاف تشغيل SELinux

إذا كان لديك نظام تشغيل CentOS/RedHat، فمن المستحسن إيقاف تشغيل SELinux. وإلا، قد تواجه الكثير من مشكلات الأذونات الغريبة.

لنتحقق مما إذا كان SELinux قيد التشغيل باستخدام الأمر التالي.

$ sestatus
SELinux status: disabled

إذا كان يشير إلى أنه قيد التشغيل (enforcing)، يمكنك إيقافه مؤقتًا باستخدام $ setenforce 0؛ أيضًا، قم بتعديل ملف /etc/selinux/config لإيقافه بشكل دائم عن طريق تغيير SELINUX=enforcing إلى SELINUX=disabled.

2. الحد الأقصى لعدد الملفات المفتوحة

ثم، تحتاج إلى التحقق من الحد الأقصى الحالي لعدد الملفات المفتوحة على النظام باستخدام الأمر التالي.

    $ cat /proc/sys/fs/file-nr
    3984 0 3255296

الرقم الأخير 3255296 هنا هو الحد الأقصى لعدد الملفات المفتوحة. إذا كان هذا الرقم صغيرًا على جهازك، فأنت بحاجة إلى تعديل ملف /etc/sysctl.conf لزيادته.

fs.file-max = 1020000
net.ipv4.ip_conntrack_max = 1020000
net.ipv4.netfilter.ip_conntrack_max = 1020000

بعد التعديل، يجب إعادة تشغيل خدمة النظام لتصبح التغييرات فعالة.

sudo sysctl -p /etc/sysctl.conf

3. حدود العملية

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

$ ulimit -n
1024

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

ulimit -n 1024000

يمكنك أيضًا تعديل ملف التكوين /etc/security/limits.conf لجعلها دائمة.

* hard nofile 1024000
* soft nofile 1024000

4. تكوين NGINX

أخيرًا، ستحتاج إلى إجراء تعديل صغير على تكوين NGINX، وهو الأسطر الثلاثة التالية من الكود.

events {
    worker_connections 10240;
}

هذا يسمح لنا بزيادة عدد الاتصالات لكل Worker. نظرًا لأن القيمة الافتراضية هي فقط 512، فهذا غير كافٍ لاختبارات الضغط العالية.

التحقق قبل اختبار الضغط

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

يمكن تقسيم هذا الاختبار الأخير إلى خطوتين.

1. استخدام الأداة الآلية c1000k

c1000k تأتي من مؤلف SSDB. كما يمكنك أن ترى من الاسم، الغرض من هذه الأداة هو التحقق مما إذا كانت بيئتك يمكن أن تلبي متطلبات 10^6 اتصال متزامن.

استخدام هذه الأداة بسيط أيضًا. نبدأ بـ server و client، يتوافق مع برنامج الخادم الذي يستمع على المنفذ 7000 وبرنامج العميل الذي يطلق اختبار الضغط لمحاكاة اختبار الضغط في بيئة حقيقية:

. /server 7000
. /client 127.0.0.1 7000

على الفور، يرسل client طلبًا إلى server للتحقق مما إذا كانت بيئة النظام الحالية يمكن أن تدعم مليون اتصال متزامن. يمكنك تشغيلها بنفسك ورؤية النتيجة.

2. التحقق مما إذا كان برنامج الخادم يعمل بشكل طبيعي

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

لذلك، فإن الخطوة الأخيرة والأكثر أهمية في اختبار بيئة الاختبار هي تشغيل مجموعة اختبارات الوحدة الخاصة بجانب الخادم أو استدعاء بعض الواجهات الرئيسية يدويًا للتأكد من أن جميع الواجهات، والعوائد، ورموز استجابة HTTP لاختبار wrk طبيعية وأنه لا توجد رسائل خطأ في logs/error.log.

إرسال الطلبات

حسنًا، الآن كل شيء جاهز للانطلاق. لنبدأ اختبار الضغط باستخدام wrk!

$ wrk -d 30 http://127.0.0.2:9080/hello
Running 30s test @ http://127.0.0.2:9080/hello
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   595.39us  178.51us  22.24ms   90.63%
    Req/Sec     8.33k   642.91     9.46k    59.80%
  499149 requests in 30.10s, 124.22MB read
Requests/sec:  16582.76
Transfer/sec:      4.13MB

لم أقم بتحديد المعلمات هنا حتى تبدأ wrk بخيطين و 10 اتصالات طويلة بشكل افتراضي. لا تحتاج إلى ضبط عدد الخيوط والاتصالات في wrk لتكون كبيرة جدًا؛ طالما يمكنك جعل البرنامج الهدف يصل إلى 100% من استخدام وحدة المعالجة المركزية، فستكون بخير.

لكن وقت اختبار الضغط يجب ألا يكون قصيرًا جدًا لأن اختبار الضغط لبضع ثوانٍ لا معنى له. وإلا، قد ينتهي اختبار الضغط قبل أن ينتهي برنامج الخادم من إعادة التحميل الساخن. في نفس الوقت، تحتاج إلى استخدام أداة مراقبة مثل top أو htop للتحقق مما إذا كان البرنامج الهدف على الخادم يعمل بنسبة 100% من استخدام وحدة المعالجة المركزية أثناء اختبار الضغط.

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

  • لا يمكن تحميل وحدة المعالجة المركزية بالكامل. هذه ليست مشكلة wrk؛ قد تكون قيود شبكة أو عملية حظر في الكود الخاص بك. يمكنك تحديد ذلك من خلال مراجعة الكود الخاص بك أو استخدام مخطط اللهب off CPU.
  • وحدة المعالجة المركزية محملة بالكامل دائمًا، حتى عند توقف الضغط. يشير هذا إلى وجود حلقة لا نهائية في الكود ناتجة عن تعبير عادي أو خطأ في LuaJIT، والذي واجهته في بيئات حقيقية. في هذه المرحلة، ستحتاج إلى استخدام مخطط اللهب لوحدة المعالجة المركزية لتحديد ذلك.

أخيرًا، دعنا نلقي نظرة على إحصائيات wrk. فيما يتعلق بهذه النتيجة، نركز بشكل عام على قيمتين.

الأولى هي QPS، أو Requests/sec: 16582.76، وهي رقم دقيق يشير إلى عدد الطلبات التي يتم معالجتها في الثانية على جانب الخادم.

الثانية هي زمن الاستجابة: Latency 595.39us 178.51us 22.24ms 90.63%، وهي بنفس أهمية QPS، وتعكس سرعة استجابة النظام. على سبيل المثال، لتطبيقات البوابة، نريد الحفاظ على زمن الاستجابة ضمن 1 مللي ثانية.

بالإضافة إلى ذلك، توفر wrk أيضًا معلمة latency التي تطبع توزيع النسبة المئوية لزمن الاستجابة بالتفصيل، على سبيل المثال.

Latency Distribution
        50% 134.00us
        75% 180.00us
        90% 247.00us
        99% 552.00us

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

الخلاصة

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

أخيرًا، سأترك لك سؤالًا: wrk تدعم نصوص Lua المخصصة لإجراء اختبار الضغط، فهل يمكنك كتابة نص Lua بسيط بناءً على وثائقها؟ قد يكون الأمر صعبًا بعض الشيء، ولكنك ستفهم نية واجهات wrk المكشوفة عند الانتهاء منه.

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