جهازان من فئة DGX Spark، نموذج واحد: نسخة على كل جهاز تتفوق على تقسيمه
العمليات
طوال سبعة أسابيع، شغّلنا نموذج اللغة المحلي لدينا مقسماً على جهازين من نوع NVIDIA GB10 باستخدام التوازي الموتر. في 22 أكتوبر، استبدلنا ذلك بنسخة كاملة من النموذج على كل جهاز مع وكيل أمامي يعتمد على أقل عدد من الاتصالات. ارتفع الإنتاج من حوالي 180 إلى 210 توكنات في الثانية، وأصبح بإمكان أي جهاز إعادة التشغيل دون فقدان النموذج.
لماذا قمنا بتقسيمه
يحتوي كل جهاز على ذاكرة سعتها 128 جيجابايت مشتركة بين المعالج المركزي ومعالج الرسوميات. في سبتمبر، كان النموذج يتسع لجهاز واحد، لكن ذاكرته المؤقتة بالكاد اتسعت: فلم تستطع نسخة vLLM التي استخدمناها إبقاء ذاكرة KV لهذا النموذج بصيغة FP8، لذا كانت الذاكرة المؤقتة بصيغة BF16، وكانت هناك مساحة لجهاز واحد لـ 499,110 توكن منها. وهذا أقل من طلبين عند السياق الكامل للنموذج البالغ 262,144 توكن. عند التقسيم على الجهازين مع التوازي الموتر عبر رابط الشبكة المباشر بينهما، نمت الذاكرة المؤقتة إلى أكثر من ثلاثة ملايين توكن. لقد قسمنا النموذج من أجل المساحة، وليس من أجل السرعة.
ما الذي تغيّر
تأخذ نسخة أحدث من النموذج نفسه بعمق 4 بت (NVFP4، مصنوعة بالتقطير الواعي بالتكميم) حوالي 71 جيب من الذاكرة، وتشغّل نسخة vLLM المجتمعية لجهاز GB10 (eugr/spark-vllm-b12x) ذاكرتها المؤقتة بصيغة FP8. الآن يستوعب جهاز واحد النموذج بأكمله وذاكرة مؤقتة تتراوح بين 0.76 و1.08 مليون توكن، مما يوفر مساحة لـ 2.9 إلى 4.1 طلب عند السياق الكامل، اعتماداً على مقدار الذاكرة التي يمنحها الجهاز. يستخدم كلتا النسختين فك التشفير التخميني الخاص بالنموذج (MTP، أربعة توكنات مسودة). قبل التبديل، أجرينا اختبار استدعاء الأدوات لدينا على النسخة الجديدة: حيث سجلت 86، بينما سجلت النسخة التي حلت محلها 75.
ما قسناه
| مقسماً على جهازين | نسخة على كل جهاز | |
|---|---|---|
| ذاكرة KV المؤقتة | أكثر من 3 ملايين توكن | 0.76 و1.08 مليون توكن |
| الطلبات عند السياق الكامل | حوالي 12 | 2.9 و4.1 |
| الإنتاج تحت حملنا | حوالي 180 توكن/ث | 210 توكن/ث (111 + 99) |
| بدء التشغيل | حوالي 20 دقيقة | 5 إلى 13 دقيقة لكل نسخة |
| إعادة تشغيل جهاز واحد | يتوقف النموذج | تخدم النسخة الأخرى |
نسخة واحدة بمفردها، بحسب عدد الطلبات التي تخدمها في آنٍ واحد: مع المطالبات القصيرة، أعطى طلب واحد 36 رمزًا في الثانية، وأعطت 4 طلبات 82، و8 طلبات 109، و16 طلبًا 150. مع مطالبات وكيل البريد الإلكتروني الأطول لدينا، أعطت 4 طلبات 81، و8 طلبات 113، و16 طلبًا 87 فقط: بعد ثمانية طلبات من هذا النوع، تؤدي المزيد من الطلبات إلى إبطاء الأداء.
خلال فترة بعد الظهر، استقبلت نسخة واحدة ما يصل إلى 12 طلبًا في آنٍ واحد، بينما استقبلت الأخرى 8 طلبات. أنتجت الأولى من 91 إلى 93 رمزًا في الثانية، وأكملت من 26 إلى 27 طلبًا في الدقيقة؛ والثانية من 81 إلى 83 رمزًا في الثانية، و22 طلبًا في الدقيقة. كلاهما يستقبل الآن 12 طلبًا.
ما تخلينا عنه
المساحة. كان للنموذج المنقسم ذاكرة تخزين مؤقتة واحدة بأكثر من ثلاثة ملايين رمز؛ أما النسخ فلكل منها ذاكرة تخزين مؤقتة أصغر، ولا يمكن للطلب استخدام ذاكرة التخزين المؤقتة إلا للنسخة التي تخدمه. ترسل وكلاؤنا العديد من الطلبات القصيرة والمتوسطة، وكان الإنتاجية أهم بالنسبة لها. إذا كنت تخدم عددًا قليلاً من السياقات الطويلة جدًا في آنٍ واحد، فقد يظل التقسيم هو الخيار الأفضل. أبقينا على إعداد التقسيم، والعودة إليه تتم عبر نص برمجي واحد.
ما حدث من أخطاء أثناء التبديل
- إحدى عشرة دقيقة دون نموذج، ثم 30 ثانية من أخطاء 502. كان على النموذج المنقسم أن يتوقف قبل أن تتمكن نسخة من التحميل على الأجهزة نفسها، لذا انتظر وكلاؤنا حوالي إحدى عشرة دقيقة. عندما ظهرت النسخة الأولى، استمر الوكيل في الرد بـ "502 لا توجد خوادم خلفية نشطة" لمدة 30 ثانية إضافية: فقد حدد الخوادم الخلفية كفاشلة أثناء توقفها (max_fails=3، fail_timeout=30s) ولم يحاول الاتصال بها مرة أخرى حتى انقضت تلك المدة.
- عميل تجاوز الوكيل. كانت إحدى مهام الدفع لدينا تحتوي على عنوان الجهاز الأول في إعداداتها، لذا ذهب حملها بالكامل إلى نسخة واحدة بينما كانت الأخرى تملك سعة فائضة. يمر كل عميل الآن عبر الوكيل؛ وتُستخدم عناوين الأجهزة نفسها فقط لفحوصات الصحة.
- مقاييس قفزت بشكل غير متوقع. كان مراقب الإنتاجية لدينا يقرأ /metrics الخاص بـ vLLM عبر الوكيل. مع خادمين خلفيين، كانت القراءات المتتالية تأتي من نسخ مختلفة، فتقافزت العدادات ذهابًا وإيابًا، وأبلغ المراقب أن النموذج يعاني من نقص الموارد. يقرأ الآن كل نسخة مباشرة ويجمع النتائج.
- مراقب قديم كان سيوقف النسخة الجديدة. كان الإعداد المنقسم يحتوي على مراقب يعيد تشغيل خدمته عندما يتوقف النموذج عن الاستجابة. تُعلن الخدمة الجديدة عن Conflicts= مع القديمة، لذا كان من شأن إعادة التشغيل تلك أن توقف النسخة الجديدة. كان يجب إيقافها باستخدام
systemctl disable --now، وليس مجرد إيقافها، لأن طبقة العمليات لدينا تعيد تشغيل الوحدات المفعّلة وغير العاملة. - الذاكرة على الجهاز الذي يؤدي أعمالًا أخرى. يشغّل جهاز واحد أيضًا قواعد البيانات وعمليات بناء الموقع لدينا. مع ضبط gpu-memory-utilization الخاص بـ vLLM على 0.78، لم يتبقَّ سوى 5 GiB لكل شيء آخر، لذا خفّضناه إلى 0.74 وأعدنا تشغيل تلك النسخة فقط بينما تحمل النسخة الأخرى العبء. على هذه الأجهزة، تأتي الحصة التي تمنحها لـ vLLM من نفس الذاكرة المخصصة لكل شيء آخر.
إذا كان لديك جهازان من هذا النوع
- إذا كان النموذج وذاكرة التخزين المؤقت التي تحتاجها تتسعان على جهاز واحد، فقم بتشغيل نسخة على كل جهاز خلف وكيل توزيع يعتمد على أقل عدد من الاتصالات. قسّم النموذج فقط عندما لا يستطيع جهاز واحد استيعاب ذاكرة التخزين المؤقت التي تحتاجها.
- وجّه كل عميل إلى الوكيل، بما في ذلك مهام الدفعة والإعدادات القديمة.
- اقرأ المقاييس من كل نسخة مباشرةً.
- امنح كل جهاز حصته الخاصة من الذاكرة، وفقًا لما يشغّل عليه من تطبيقات أخرى.
- اضبط عدد الطلبات التي تخدمها النسخة في وقت واحد بناءً على حركة المرور الخاصة بك: في مزيجنا، كان 12 أفضل من 8.
- توقع أن يستغرق التبديل وقتًا يساوي وقت تشغيل النسخة لإزالة النموذج، وخطط لذلك.
Factory Floor توفر الوكيل وإعدادات التشغيل لجهاز واحد أو جهازين، وفحص الصحة واختبار استخدام الأدوات الذي نجريه قبل تبديل النماذج، مع المراقبين وحراس الذاكرة لبقية الجهاز.