چیت‌شیت

مقیاس‌بندی خودکار GPU در Kubernetes

GPU Autoscaling on Kubernetes

نودها با Karpenter، زمان‌بندی هم‌زمان با KAI Scheduler، رپلیکاها بر اساس عمق صف، مسیریابی آگاه از کش، استوری‌بوردهای رویداد.

  • ۱۲ بخش
  • ۳ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. وظایف
  2. قطع سرویس ایمن برای استخرهای GPU
  3. سه لایه‌ی مقیاس‌بندی خودکار
  4. استراتژی‌های مقیاس‌بندی در main.py
  5. ثابت‌های شبیه‌ساز
  6. مسیریابی آگاه از کش
  7. عیب‌یابی
  8. پروژه‌ی استوری‌بورد رویداد
  9. مراحل استوری‌بورد
  10. خطاهای استوری‌بورد
  11. پرسش و پاسخ
  12. نکات کاربردی

وظایف

کار و کد
وظیفهکد
توقف تخلیه (eviction) جاب‌های GPUconsolidationPolicy: WhenEmpty
تجمیع نودهای خالی پس از یک ساعتconsolidateAfter: 1h
اجتناب از رفتار پیش‌فرض تخلیهnot `WhenEmptyOrUnderutilized`
عدم مقیاس‌بندی بر اساس چرخه‌ی کاریnot `DCGM_FI_DEV_GPU_UTIL`
آماده نگه‌داشتن یک رپلیکاmin_workers=1
بوت نودها با وزن‌ها روی NVMesnapshot ID in `EC2NodeClass`
مسیریابی بر اساس پیشوند کِش‌شدهkv.cache.block_added
مقایسه‌ی سه روش مقیاس‌بندیsimulate(strategy, reqs)

قطع سرویس ایمن برای استخرهای GPU

کد
yaml
# ‏Karpenter NodePool، استخر GPU
disruption:
  consolidationPolicy: WhenEmpty  # هرگز جاب در حال اجرا را تخلیه نکنید
  consolidateAfter: 1h            # تجمیع نودهای خالی پس از یک ساعت

سه لایه‌ی مقیاس‌بندی خودکار

معماری
پروویژنافزودن نودهمه یا هیچاستقرارمصرفمقیاس‌بندیانتشارپادهای در انتظار (Pending)نیاز به 8 عدد H100Karpenter‏NodePool، حدود 45 تا 60 ثانیهنود GPUدامنه NVLinkKAI Schedulerزمان‌بندی هم‌زمان، توپولوژی، صف‌ها‏Dynamo Planner / llm-d WVAرپلیکاهاسیگنال‌هاعمق صف، میزان مصرف KVرپلیکاهای vLLMپاسخ‌دهی به درخواست‌ها

استراتژی‌های مقیاس‌بندی در main.py

مقایسه
فاکتورDUTY_CYCLEQUEUE_DEPTHKAI_GANG
سیگنالDCGM_FI_DEV_GPU_UTILlen(queue)len(queue)
افزایش مقیاس زمانی کهutil > TARGET_GPU_UTILqd > 5qd > 3
گام افزایشreplicas_target += 1max(1, qd // 5)max(2, qd // 3)
کاهش مقیاس زمانی کهutil < 20qd == 0qd == 0
نتیجهدرخواست‌ها را دور می‌ریزدبه انباشتگی صف (backlog) واکنش نشان می‌دهداز توقف‌های تخصیص ناقص جلوگیری می‌کند

ثابت‌های شبیه‌ساز

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
NODE_PROVISION_SEC50‏Karpenter حدود 45 تا 60 ثانیه
CLUSTER_AUTOSCALER_SEC110مقایسه‌ی کندتر
MODEL_LOAD_SEC45وزن‌های 70B به‌علاوه‌ی راه‌اندازی موتور
HPA_TICK_SEC15بازه حلقه‌ی کنترل
TARGET_GPU_UTIL70هدف چرخه‌ی کاری
MAX_REPLICAS16سقف رپلیکا
CACHE_HIT_MS80‏TTFT با پیشوند مقیم در کش
CACHE_MISS_MS800‏TTFT در پیش‌پرکنی سرد (cold prefill)

مسیریابی آگاه از کش

گام‌به‌گام
  1. مسیریابپیشوند را هش می‌کند، برای مثال 512 توکن اول.
  2. رپلیکاهابا تخصیص و آزادسازی بلوک‌ها، رویدادهای کش کلید-مقدار را منتشر می‌کنند.
  3. مسیریاب vLLMرویداد kv.cache.block_added را به نگاشت هش پیشوند به رپلیکا ایندکس می‌کند.
  4. مسیریابدرخواست را به رپلیکای دارای انطباق ارسال می‌کند.
  5. مسیریابدر صورت عدم تطابق، کمترین عمق صف را انتخاب می‌کند.
  6. مسیریاب سراسریمقدار RTT را به هزینه‌ی اصابت می‌افزاید. اگر هزینه از CACHE_MISS_MS بگذرد، محلی می‌ماند.
  7. محل اقامت داده (Residency)پیش از کش، مسیریاب‌ها را بر اساس مرز اقامت داده‌ها پارتیشن‌بندی کنید.

عیب‌یابی

عیب‌یابی
  • ‏HPA هرگز در 100٪ مقیاس‌بندی نمی‌شود

    علت
    چرخه‌ی کاری تفاوت 10 یا 100 درخواست را پنهان می‌کند
    راه‌حل
    مقیاس‌بندی بر اساس عمق صف یا میزان مصرف KV
  • ‏HPA بر اساس حافظه هرگز کاهش نمی‌یابد

    علت
    ‏vLLM کش کلید-مقدار را از پیش تخصیص می‌دهد
    راه‌حل
    حذف حافظه به عنوان سیگنال
  • 7 پاد از 8 پاد منتظر می‌مانند و هزینه می‌سوزانند

    علت
    نبود زمان‌بندی هم‌زمان (gang scheduling)
    راه‌حل
    ‏KAI Scheduler، همه یا هیچ
  • اینفرنسِ در حال اجرا تخلیه (evict) شد

    علت
    WhenEmptyOrUnderutilized
    راه‌حل
    WhenEmpty به‌همراه consolidateAfter: 1h
  • درخواست در ساعت 2 بامداد تایم‌اوت می‌شود

    علت
    پروویژن نود 3 دقیقه طول کشید
    راه‌حل
    ‏Karpenter به‌همراه یک استخر نمونه‌های آماده (warm pool)
  • نرخ اصابت کش به 8٪ کاهش می‌یابد

    علت
    لودبالانسر نوبت‌گردشی (Round-robin)
    راه‌حل
    مسیریاب آگاه از کش
  • رپلیکا در سناریوی DR اجرا نمی‌شود

    علت
    توکنایزر یا کانفیگ کوانتیزاسیون سینک نشده است
    راه‌حل
    پشتیبان‌گیری از مانیفست بازیابی فاجعه (DR) سه‌فایلی
  • یک HPA واحد برای پیش‌پرکنی و رمزگشایی

    علت
    دو کلاس پاد، دو محرک متفاوت
    راه‌حل
    ‏HPA مجزا به‌ازای هر نقش روی Services تفکیک‌شده

پروژه‌ی استوری‌بورد رویداد

کد
bash
python3 scripts/project_test.py kubernetes-event-storyboard --init /tmp/kubernetes-event-storyboard-work
python3 scripts/project_test.py kubernetes-event-storyboard --stage 1 --path /tmp/kubernetes-event-storyboard-work --strict
python3 scripts/project_test.py kubernetes-event-storyboard --all --solution --strict
cd projects/kubernetes-event-storyboard/solution
go run . --input fixtures/rollout.json --out /tmp/context-pack.json               # پک Go
node --experimental-strip-types cli.ts /tmp/context-pack.json /tmp/timeline.html  # HTML
kubectl get events -A -o json                                                     # خروجی گرفتن از اسنپ‌شات اختصاصی

مراحل استوری‌بورد

گام‌به‌گام
  1. تجزیه (Parse)تابع Parse([]byte)(Bundle,error) مقادیر observedAt و هر دو آرایه‌ی اقلام را بررسی می‌کند.
  2. گروه‌بندی (Group)تابع Group(Bundle)([]Row,error) بیشترین تعداد را به‌ازای UID هر رویداد نگه می‌دارد، سپس جمع می‌زند.
  3. اتصال (Connect)پیمایش ownerReferences به deployment.kubernetes.io/revision.
  4. خروجی گرفتن (Export)تابع Export(Bundle)(Pack,error) ساختار schemaVersion نگارش 1 را با پاک‌سازی داده‌های حساس می‌نویسد.
  5. ‏parsePackتابع parsePack(text) نگارش، شمارش‌ها و ترتیب زمانی را بررسی می‌کند.
  6. تایم‌لاین (timeline)تابع timeline(pack) کد HTML اسکیپ‌شده را همراه با فیلتر Warning بازمی‌گرداند.

خطاهای استوری‌بورد

دستورها
دستورعملکرد
bundle exceeds one MiBورودی بیش از 1<<20 بایت است
trailing JSONداده‌های اضافی پس از باندل
observedAt must be RFC3339برچسب زمانی ثبت نامعتبر است
invalid occurrence range or countپایان قبل از آغاز، یا تعداد کمتر از 1
event UID changed identity‏UID برای آبجکت یا علت دیگری مجدداً استفاده شده است
invalid or duplicate workload UID‏UID ورک‌لود خالی یا تکراری است
invalid context pack‏TypeScript پک Go را رد می‌کند

پرسش و پاسخ

پرسش و پاسخ
‏Karpenter یا Cluster Autoscaler؟
‏Karpenter حدود 45-60 ثانیه زمان می‌برد؛ Cluster Autoscaler برای نودهای GPU حدود 90-120 ثانیه است.
کدام سیگنال برای پادهای پیش‌پرکنی مناسب است؟
عمق صف. پادهای رمزگشایی بر اساس فشار روی کش کلید-مقدار مقیاس می‌یابند.
مسیریابی بین ریجن‌ها انجام شود؟
به‌ندرت. 440 میلی‌ثانیه رفت‌وبرگشت، صرفه‌جویی 800 به 80 میلی‌ثانیه را بی‌اثر می‌کند.
هزینه‌ی الگوریتم نوبت‌گردشی چیست؟
اصابت به کش حدود 80 میلی‌ثانیه و عدم اصابت حدود 800 میلی‌ثانیه است؛ اختلافی 10 برابری.
دو اسنپ‌شات با تعدادهای 2 و 4؟
یک سری واحد است؛ تعداد نهایی 4 است، نه 6.
دو نسخه (revision) یافت شد؟
نسخه نامشخص می‌ماند؛ هرگز بر اساس نام‌ها حدس نزنید.

نکات کاربردی

نکته‌ها
  • از tokenizer.json یا tokenizer.model در کنار وزن‌ها نسخه‌ی پشتیبان بگیرید.
  • از quantize_config.json و vllm_config.yaml پشتیبان بگیرید.
  • تمرین مانور بازیابی فاجعه (DR) را به‌صورت فصلی اجرا کنید.
  • ‏KAI را به‌عنوان اسکژولر ثانویه اجرا کرده و ورک‌لودها را برای استفاده از آن برچسب‌گذاری (annotate) کنید.
  • ورک‌لود با موازی‌سازی تنسور (tensor-parallel) را روی یک دامنه‌ی NVLink نگه دارید.
  • مقدار min_workers=1-2 را فقط به مسیرهای چت زنده و صوتی اختصاص دهید.