مقدمة: ما وراء خدمات الميكروستندارد
تعمل أنظمة استدلال نماذج اللغة الكبيرة (LLM) تحت قيود فريدة تختلف عن خدمات الميكروستندارد التقليدية. على عكس واجهات برمجة التطبيقات (APIs) غير الحية (stateless)، تعتمد نقاط نهاية LLM بشكل كبير على ذاكرة GPU المحدودة لإدارة ذاكرة KV cache، وغالبًا ما تحافظ على اتصالات طويلة الأمد لتدفق الاستجابات. هذا الاعتماد على الأجهزة المتخصصة يجعل ممارسات هندسة الفوضى القياسية غير كافية. لا يمكننا ببساطة إنهاء حاوية؛ بل يجب أن نأخذ في الاعتبار الحالة المخزنة في VRAM، وتكلفة إعادة تهيئة النموذج، وارتفاعات الكمون (latency spikes) الناتجة عن دورات إعادة تعيين GPU.
في هذه المقالة، نستكشف كيفية تصميم تجارب فوضى تستهدف بشكل محدد أعطال GPU وانقطاعات الشبكة. الهدف هو الانتقال من "يعود للعمل" إلى "يعود للعمل بكمون مقبول وبدون فقدان البيانات لعملاء التدفق (streaming clients)".
السيناريو 1: محاكاة عطل مفاجئ في GPU
نمط فشل شائع في الإنتاج هو سقوط GPU من ناقل PCI بسبب التبريد الحراري (thermal throttling) أو انهيار برامج التشغيل. في بيئات Kubernetes التي تعمل ببرامج تشغيل NVIDIA، غالبًا ما يتجلى هذا في عزل العقدة (cordon-ed off) أو انهيار الحاوية (pod) مع خطأ `SIGBUS`.
لاختبار هذا، نحتاج إلى محاكاة فقدان جهاز الحساب دون إعادة تشغيل العقدة بأكملها بالضرورة، حيث يمكن أن يخفي وقت استجابة المنسق (orchestrator) معالجة الأخطاء الداخلية للتطبيق.
يمكننا استخدام `nvidia-smi` مع نداءات النظام (system calls) لمحاكاة هذا، أو بشكل أكثر عملية، حقن انهيار في عملية خادم الاستدلال بينما يكون GPU تحت حمل.
#!/bin/bash
# chaos_gpu_crash.sh
# يحقن SIGBUS في عملية الاستدلال لمحاكاة فشل وصول GPU
PID=$(pgrep -f "vllm.engine" | head -n 1)
if [ -z "$PID" ]; then
echo "لم يتم العثور على عملية الاستدلال"
exit 1
fi
echo "محاكاة فشل وصول ذاكرة GPU على PID $PID"
# غالبًا ما يتم رفع SIGBUS عندما تكون الذاكرة غير مرسومة (unmapped)، مما يحاكي خطأ وصول VRAM
kill -BUS $PID
**المقاييس الرئيسية للمراقبة:**
* **كمون البدء البارد (Cold Start Latency):** كم من الوقت يستغرق حتى يتم تقديم الطلب التالي بواسطة نسخة صحية؟
* **سلوك إعادة المحاولة لدى العميل:** هل تعيد موازنات الأحمال أو العملاء المحاولة فورًا؟ إذا كان الأمر كذلك، هل أنت تغرق العقد الصحية المتبقية بالحمولة المتراكمة؟
* **فقدان ذاكرة KV Cache:** تأكد من أن أي توليد جزئي قيد التنفيذ يتم إنهاؤه بشكل صحيح أو استئنافه من نقطة تفتيش (checkpoint) إذا كان إطار العمل الخاص بك يدعم ذلك.
السيناريو 2: انقطاعات الشبكة والعقد المتأخرة (Straggler Nodes)
في إعدادات الاستدلال الموزع (مثل استخدام DeepSpeed أو توازي التوتنر (tensor parallelism) في vLLM)، فإن انقطاع الشبكة أمر حاسم. إذا فقدت عقدة واحدة في مجموعة توازي التوتنر الاتصال، فإن دفعة الاستدلال بأكملها تفشل. ومع ذلك، في البنية المعمارية المفككة (فصل Prefill عن Decode)، يسبب انقطاع بين موازن الأحمال الأمامي وعملات الاستدلال أعراضًا مختلفة.
لنقم بمحاكاة انقطاع شبكة يصبح فيه الخلفية الخلفية (inference backend) غير قابلة للوصول بينما يبقى بوابة API (API gateway) قيد التشغيل.
# استخدم tc (ضبط حركة المرور) لإدخال 100% من فقدان الحزم إلى حاوية الخلفية الخلفية
# يحاكي هذا انقطاع الشبكة دون إسقاط العقدة بأكملها
POD_IP=$(kubectl get pod -l app=inference-backend -o jsonpath='{.items[0].status.podIP}')
# إسقاط جميع حركة المرور المتجهة إلى الخلفية الخلفية
kubectl exec -it [gateway-pod] -- tc qdisc add dev eth0 root netem loss 100%
# انتظر نافذة الفوضى
sleep 30
# استعادة حركة المرور
kubectl exec -it [gateway-pod] -- tc qdisc del dev eth0 root
**السلوك المتوقع:**
1. يجب أن تنتهي مهلة الطلبات في بوابة API ضمن `proxy_read_timeout` المهيأ (مثلاً، 5 ثوانٍ).
2. يجب على البوابة الفشل بسرعة (fail-fast) إلى نسخ بديلة إذا كانت متاحة.
3. **بشكل حاسم:** للاستجابات المتدفقة (SSE)، يجب على العميل اكتشاف الاتصال المغلق. اختبر ما إذا كان كود جهة العميل الخاص بك يتعامل بشكل صحيح مع انقطاع منتصف التدفق ويعيد طابور الموجه (prompt)، أم يفشل بصمت، مما يؤدي إلى إحباط المستخدم.
تنفيذ اختبارات الفوضى الآلية في CI/CD
اختبار الفوضى اليدوي غير مستدام. قم بدمج هذه السيناريوهات في خط أنابيب الاختبار (staging pipeline) الخاص بك باستخدام أدوات مثل LitmusChaos أو Chaos Mesh.
apiVersion: litmuschaos.github.io/v1alpha1
kind: ChaosExperiment
metadata:
name: llm-gpu-chaos
spec:
appinfo:
appkind: deployment
labelselector: "app=vllm-server"
chaosConfig:
chaosKind: "pod-kill"
# محاكاة إنهاء قسري لتفعيل استعادة GPU على مستوى العقدة
mode: "all"
duration: "120s"
**استراتيجية التحقق:**
لا تكتفِ بالتحقق من إعادة تشغيل الحاوية (pod). تحقق من *جودة* الخدمة.
* **فحص كمون P99:** اطلب أن لا يتجاوز كمون P99 ضعف خط الأساس (baseline) خلال نافذة الفشل.
* **فحص فقدان الرموز (Tokens):** للتدفق، تحقق من أن إجمالي الرموز المستلمة من قبل العميل يطابق العدد المتوقع أو أن خطأً نظيفًا يُعاد، بدلاً من استجابة مقطوعة وفاصلة.
الخاتمة
استدلال LLM ليس مجرد خدمة غير حية أخرى. طبيعته الحية (statefulness) في VRAM، وحجم ذاكرته الكبير، وطبيعته المتدفقة طويلة الأمد تتطلب نهجًا متخصصًا لهندسة الفوضى. من خلال محاكاة أعطال GPU وانقطاعات الشبكة، يمكنك كشف فجوات حاسمة في منطق إعادة المحاولة الخاص بك، واستراتيجيات موازنة الأحمال، ومعالجة الأخطاء على جانب العميل. ابدأ صغيرًا: حقن عطل GPU واحد في بيئة الاختبار. راقب نطاق التأثير (blast radius). كرر. المرونة تُبنى من خلال الفشل المتعمد.