فاز 17 · درس 3

مقیاس‌بندی خودکار GPU در کوبرنتیز با Karpenter و KAI Scheduler

نوع
مفهومی
زمان
حدود 75 دقیقه
زبان‌ها
Python (stdlib, toy queue-depth autoscaler simulator)
پیش‌نیاز
فاز 17 · 02 (اقتصاد پلتفرم استنتاج)، فاز 17 · 04 (سازوکار درونی موتورهای سرویس‌دهی)
یک طرح مفهومی از سه لایه چرخ‌دنده و زنجیره سخت‌افزاری سرور که پردازنده‌های گرافیکی را در تعادل نگه داشته‌اند
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. لایه‌ی 1 — آماده‌سازی نود (Karpenter)
  5. لایه‌ی 2 — زمان‌بندی هم‌زمان (KAI Scheduler)
  6. لایه‌ی 3 — سیگنال‌های سطح برنامه
  7. چه ابزاری را چه زمانی استفاده کنیم؟
  8. تفکیک پیش‌پرکنی/رمزگشایی همه‌چیز را پیچیده‌تر می‌کند
  9. شروع سرد اینجا هم اهمیت دارد
  10. اعدادی که باید به خاطر بسپارید
  11. استفاده در عمل
  12. تحویل نهایی
  13. تمرین‌ها
  14. اصطلاحات کلیدی
  15. منابع بیشتر

اجرای مدل‌های زبانی بزرگ روی کوبرنتیز چالش‌های هزینه‌ای و فنی سنگینی به همراه دارد. تکیه بر ابزارهای سنتی مثل HPA و معیارهای ساده‌ی مصرف پردازنده معمولاً منجر به فریب سیستم می‌شود؛ چون ماهیت حافظه‌ی پیش‌تخصیص‌یافته در موتورهایی مثل vLLM رفتار متفاوتی با بارهای کاری وب دارد. در این وضعیت، نودهای گران‌قیمت یا بی‌دلیل روشن می‌مانند یا در میانه‌ی پاسخ‌دهی به درخواست‌ها خاموش می‌شوند.

از سوی دیگر، با توجه به اینکه اجاره‌ی GPUهای ابری خارجی به دلیل موانع پرداخت ارزی و محدودیت‌های دسترسی بسیار پرهزینه و دشوار است، هر دقیقه هدررفت منابع پردازشی مستقیماً به زیان مالی پروژه تمام می‌شود. خطاهایی مانند معطل ماندن چند نود برای آماده شدن یک GPU دیگر، منابع مالی محدودی را که با زحمت فراهم شده می‌سوزاند.

این درس به شما می‌آموزد چگونه یک معماری سه‌لایه‌ای متشکل از Karpenter برای آماده‌سازی سریع نودها، KAI Scheduler برای زمان‌بندی هم‌زمان (Gang scheduling) و سیگنال‌های سطح برنامه (مانند عمق صف) بسازید تا کلاستر شما بدون افت کارایی یا تحمیل هزینه‌های اضافه، با بارهای کاری ناگهانی سازگار شود.

سه لایه، نه یکی. Karpenter نودها را به‌صورت پویا آماده‌سازی (Provision) می‌کند (زیر 1 دقیقه؛ 40% سریع‌تر از Cluster Autoscaler). وظیفه‌ی زمان‌بندی هم‌زمان یا گنگ (Gang scheduling)، آگاهی از توپولوژی (Topology awareness) و صف‌های سلسله‌مراتبی (Hierarchical queues) بر عهده‌ی KAI Scheduler است؛ ابزاری که جلوی تله‌ی تخصیص ناقص 7 از 8 را می‌گیرد؛ حالتی که در آن هفت نود بیهوده منتظر یک GPU باقی‌مانده می‌مانند و هزینه می‌سوزانند. مقیاس‌پذیرهای سطح برنامه (مانند NVIDIA Dynamo Planner و llm-d Workload Variant Autoscaler) بر اساس سیگنال‌های اختصاصی استنتاج مقیاس‌بندی می‌کنند؛ یعنی عمق صف (Queue depth) و میزان استفاده از کش کلید-مقدار (KV cache utilization)، نه چرخه‌ی کاری (Duty cycle) مربوط به CPU یا DCGM. تله‌ی کلاسیک HPA این است که DCGM_FI_DEV_GPU_UTIL صرفاً چرخه‌ی کاری را اندازه می‌گیرد: استفاده‌ی 100% می‌تواند به معنای 10 درخواست باشد یا 100 درخواست. از طرفی vLLM حافظه‌ی کش کلید-مقدار را از قبل تخصیص می‌دهد؛ بنابراین میزان مصرف حافظه هیچ‌وقت باعث مقیاس‌بندی کاهشی نمی‌شود. در این درس یاد می‌گیرید که چطور این سه لایه را ترکیب کنید و از سیاست پیش‌فرض WhenEmptyOrUnderutilized در Karpenter که جاب‌های پردازشی GPU را در میانه‌ی استنتاج متوقف می‌کند، دور بمانید.

اهداف یادگیری

  • دیاگرام سه لایه‌ی مقیاس‌بندی خودکار (آماده‌سازی نود، زمان‌بندی هم‌زمان و سطح برنامه) را رسم کنید و ابزار مورد استفاده در هر لایه را نام ببرید.
  • توضیح دهید چرا DCGM_FI_DEV_GPU_UTIL سیگنال نادرستی برای HPA در vLLM است و دو جایگزین آن را نام ببرید (عمق صف و استفاده از کش کلید-مقدار).
  • زمان‌بندی هم‌زمان و حالت شکستی را که KAI Scheduler مانع آن می‌شود (بیکار ماندن 7 تا از 8 پردازنده‌ی GPU به خاطر تخصیص ناقص)، شرح دهید.
  • سیاست یکپارچه‌سازی Karpenter را که جاب‌های فعال GPU را متوقف می‌کند (WhenEmptyOrUnderutilized) نام ببرید و جایگزین امن آن برای سال 2026 را مشخص کنید.

صورت مسئله

تیم شما در حال انتشار یک سرویس ارائه‌ی مدل‌های زبانی روی Kubernetes است. شما HPA را با سیگنال DCGM_FI_DEV_GPU_UTIL پیکربندی می‌کنید. این سرویس در ساعات اوج کاری روی 100% استفاده قفل می‌شود. HPA هیچ‌وقت مقیاس را بالا نمی‌برد؛ چون تصور می‌کند ظرفیت سیستم کاملاً پر است. شما دستی یک رپلیکا اضافه می‌کنید؛ زمان رسیدن به اولین توکن (TTFT) افت می‌کند، اما HPA باز هم مقیاس‌بندی نمی‌کند. سیگنال به شما دروغ می‌گوید.

از طرف دیگر، برای نودها از Cluster Autoscaler استفاده می‌کنید. ساعت 2 نیمه‌شب پرامپتی با 1 میلیون توکن می‌رسد؛ کلاستر 3 دقیقه وقت صرف بالا آوردن یک نود می‌کند و مهلت درخواست به پایان می‌رسد (Timeout).

باز هم در نقطه‌ای دیگر، مدلی 70 میلیاردی را دیپلوی می‌کنید که به 8 عدد GPU روی 2 نود نیاز دارد. کلاستر 7 عدد GPU آزاد دارد که روی 3 نود پخش شده‌اند و به 1 پردازنده‌ی دیگر نیاز است. Cluster Autoscaler نودی برای آن 1 پردازنده‌ی باقی‌مانده آماده می‌کند. آن 7 پردازنده‌ی رزروشده 4 دقیقه دست‌نخورده می‌مانند و منابع مالی را می‌سوزانند تا در نهایت Kubernetes بتواند آخرین GPU را آماده به کار کند.

سه لایه و سه حالت شکست کاملاً متفاوت. مقیاس‌بندی خودکار و آگاه به GPU در سال 2026 صرفاً «روشن کردن HPA» نیست؛ بلکه ترکیب آماده‌سازی نود، زمان‌بندی هم‌زمان و مقیاس‌بندی بر اساس سیگنال‌های برنامه است.

مفاهیم پایه

لایه‌ی 1 — آماده‌سازی نود (Karpenter)

ابزار Karpenter پادهای در حالت انتظار (Pending) را زیر نظر می‌گیرد و نودها را ظرف حدود 45 تا 60 ثانیه بالا می‌آورد (این زمان برای Cluster Autoscaler در نودهای GPU معمولاً 90 تا 120 ثانیه است). این ابزار نوع نمونه‌ها (Instance types) را بر اساس محدودیت‌های NodePool به‌صورت پویا انتخاب می‌کند؛ اگر پاد شما به 8 عدد H100 نیاز داشته باشد و کلاستر نود مناسبی نداشته باشد، Karpenter خودش مستقیماً نود جدیدی می‌سازد، نه اینکه ظرفیت گروه‌های موجود را بالا ببرد.

تله‌ی یکپارچه‌سازی (Consolidation): سیاست پیش‌فرض Karpenter یعنی consolidationPolicy: WhenEmptyOrUnderutilized برای استخرهای پردازشی GPU خطرناک است. این سیاست برای انتقال پادها به نمونه‌ای ارزان‌تر و متناسب‌تر، نود GPU در حال اجرا را متوقف می‌کند. در بارهای کاری استنتاج، این یعنی بیرون راندن درخواست‌های زنده و بارگذاری دوباره‌ی یک مدل 70 میلیاردی روی نود جدید؛ زیانی معادل چند دقیقه افت ظرفیت و خطای اجرای درخواست‌ها.

تنظیمات امن برای استخرهای GPU:

disruption:
  consolidationPolicy: WhenEmpty
  consolidateAfter: 1h

این تنظیم به Karpenter اجازه می‌دهد نودهایی را که واقعاً خالی هستند پس از یک ساعت جمع‌آوری کند، اما هیچ‌وقت جاب در حال اجرا را متوقف نمی‌کند.

لایه‌ی 2 — زمان‌بندی هم‌زمان (KAI Scheduler)

اسکژولر KAI (پروژه‌ای که ابتدا «Karp» نام داشت و بعداً تغییر نام داد) مواردی را مدیریت می‌کند که kube-scheduler پیش‌فرض توانایی انجامشان را ندارد:

زمان‌بندی هم‌زمان (Gang scheduling) — زمان‌بندی بر اساس قاعده‌ی «همه یا هیچ». پاد استنتاج توزیع‌شده‌ای که به 8 پردازنده نیاز دارد، یا هر 8 تا با هم اجرا می‌شوند یا هیچ‌کدام شروع به کار نمی‌کنند. بدون این قابلیت، گرفتار تله‌ی تخصیص ناقص می‌شوید: 7 پاد از 8 پاد اجرا می‌شوند، نامحدود منتظر می‌مانند و هزینه هدر می‌دهند.

آگاهی از توپولوژی (Topology awareness) — دانستن اینکه کدام پردازنده‌ها از طریق NVLink متصل هستند، کدام‌ها در یک رک قرار دارند و ارتباط InfiniBand بین کدام پردازنده‌هاست؛ و در نتیجه جای‌گذاری پادها بر همین اساس. بار کاری با موازی‌سازی تنسوری در DeepSeek-V3 67B حتماً باید در دامنه‌ی یک NVLink باقی بماند؛ KAI Scheduler این قید را کاملاً رعایت می‌کند.

صف‌های سلسله‌مراتبی (Hierarchical queues) — رقابت چند تیم بر سر یک استخر GPU مشترک با اولویت‌ها و سهمیه‌های مشخص. فشار کاری محیط عملیاتی (پروداکشن) تیم A تنها در صورتی با جاب آموزشی تیم B جایگزین و متوقف (Preempt) می‌شود که قوانین اولویت‌بندی اجازه دهند.

اسکژولر KAI در کنار kube-scheduler به‌عنوان زمان‌بند ثانویه دیپلوی می‌شود و شما بارهای کاری خود را با برچسب (Annotation) به آن هدایت می‌کنید. استک‌های پروداکشن Ray و vLLM هر دو با آن یکپارچه می‌شوند.

لایه‌ی 3 — سیگنال‌های سطح برنامه

تله‌ی HPA: معیار DCGM_FI_DEV_GPU_UTIL شاخصی از جنس چرخه‌ی کاری است؛ یعنی در هر بازه‌ی نمونه‌برداری فقط می‌سنجد که پردازنده در حال کار بوده یا نه. استفاده‌ی 100% می‌تواند به معنای 10 درخواست هم‌زمان باشد یا 100 درخواست؛ در هر دو حالت پردازنده مشغول بوده است. مقیاس‌بندی بر مبنای چرخه‌ی کاری، مقیاس‌بندی کورکورانه است.

بدتر اینکه vLLM و موتورهای مشابه، حافظه‌ی کش کلید-مقدار را از قبل رزرو می‌کنند (تا سقف --gpu-memory-utilization). بنابراین مصرف حافظه حتی با یک درخواست هم نزدیک 90% می‌ماند. در نتیجه HPA مبتنی بر حافظه هیچ‌وقت مقیاس را کاهش نمی‌دهد.

سیگنال‌های جایگزین سال 2026:

  • عمق صف (تعداد درخواست‌های منتظر برای پیش‌پرکنی (Prefill)).
  • میزان استفاده از کش کلید-مقدار (چه نسبتی از بلوک‌ها به توالی‌های فعال تخصیص یافته است).
  • زمان P99 TTFT در هر رپلیکا (سیگنال توافق‌نامه‌ی سطح خدمات یا SLA شما).
  • بازدهی مفید (Goodput) (تعداد درخواست‌هایی در ثانیه که همه‌ی الزامات SLO را برآورده می‌کنند).

ابزارهای NVIDIA Dynamo Planner و llm-d Workload Variant Autoscaler این سیگنال‌ها را دریافت می‌کنند و رپلیکاها را مقیاس می‌دهند. آن‌ها برای سرویس‌دهی مدل‌های زبانی، به‌طور کامل جایگزین HPA می‌شوند.

چه ابزاری را چه زمانی استفاده کنیم؟

تصمیم مقیاس‌بندی ابزار
افزودن/حذف نودها Karpenter
زمان‌بندی جاب‌های چند پردازنده‌ای KAI Scheduler
افزودن/حذف رپلیکاها Dynamo Planner / llm-d WVA (یا HPA سفارشی بر اساس عمق صف)
انتخاب نوع GPU Karpenter NodePool
آزادسازی اجباری منابع اولویت پایین (Preempt) صف‌های KAI Scheduler

تفکیک پیش‌پرکنی/رمزگشایی همه‌چیز را پیچیده‌تر می‌کند

اگر معماری تفکیک‌شده‌ی پیش‌پرکنی/رمزگشایی (فاز 17 · 17) را اجرا می‌کنید، دو دسته پاد با محرک‌های مقیاس‌بندی متفاوت دارید: پادهای پیش‌پرکنی بر اساس عمق صف مقیاس می‌گیرند و پادهای رمزگشایی (Decode) بر اساس فشار کش کلید-مقدار. ابزار llm-d این‌ها را به‌صورت Services مجزا با HPA اختصاصی برای هر نقش ارائه می‌دهد. سعی نکنید یک HPA واحد را جلوی هر دو قرار دهید.

شروع سرد اینجا هم اهمیت دارد

کاهش زمان شروع سرد (Cold-start mitigation) (فاز 17 · 10) جایی است که زمان آماده‌سازی نود مستقیماً روی تجربه‌ی کاربر اثر می‌گذارد. زمان 45 تا 60 ثانیه‌ای برای آماده‌سازی Karpenter به‌اضافه‌ی بارگذاری یک مدل 20 گیگابایتی و راه‌اندازی اولیه‌ی موتور، باعث می‌شود پاسخ به یک درخواست در حالتی که هیچ نودی بالا نیست بین 2 تا 5 دقیقه طول بکشد. برای مسیرهای بحرانی (Critical paths) وابسته به SLO، همیشه یک استخر آماده و گرم (min_workers=1) نگه دارید، یا در لایه‌ی برنامه از چک‌پوینت‌گیری (Checkpointing) به سبک Modal بهره ببرید.

اعدادی که باید به خاطر بسپارید

  • آماده‌سازی نود در Karpenter: حدود 45-60 ثانیه در مقایسه با 90-120 ثانیه در Cluster Autoscaler (برای نودهای GPU).
  • KAI Scheduler مانع از هدررفت منابع بر اثر تخصیص ناقص می‌شود — تله‌ی 7 از 8.
  • استفاده از DCGM_FI_DEV_GPU_UTIL به‌عنوان سیگنال HPA: اشتباه است؛ از عمق صف یا استفاده از کش کلید-مقدار استفاده کنید.
  • گزینه‌ی WhenEmptyOrUnderutilized در Karpenter: جاب‌های در حال اجرای GPU را متوقف می‌کند. برای بار استنتاج از WhenEmpty + consolidateAfter: 1h استفاده کنید.
مقیاس‌پذیری خودکار (AUTOSCALING)بار ورودی را بکشید
AUTOSCALINGAn autoscaler adds and removes replicas so that the offered load stays within capacity and latency holds under its target. The replica count is the load divided by what one replica can serve, rounded up. Raise the QPS and replicas spin up; lower it and they scale back down, which is what keeps both latency and cost in check.
اتواسکيلر (مقیاس‌پذیر خودکار) رپلیکاها را کم و زیاد می‌کند تا بار ارائه‌شده در محدوده ظرفیت باقی بماند و تاخیر از حد هدف فراتر نرود. تعداد رپلیکا برابر است با تقسیم بار بر ظرفیت سرویس‌دهی یک رپلیکا، گردشده به بالا. با افزایش QPS رپلیکاها فعال می‌شوند و با کاهش آن مقیاس کاهش می‌یابد؛ امری که هم تاخیر و هم هزینه را در کنترل نگه می‌دارد.

استفاده در عمل

اسکریپت code/main.py یک سیستم مقیاس‌پذیری خودکار سه لایه را روی بار کاری با ترافیک ناگهانی و انفجاری GPU شبیه‌سازی می‌کند. این کد HPA ساده (بر مبنای چرخه‌ی کاری)، HPA بر مبنای عمق صف و مقیاس‌بندی هم‌زمان بر اساس KAI را مقایسه کرده و تعداد درخواست‌های بی‌پاسخ، دقایق بیکاری GPU و یک امتیاز ترکیبی را گزارش می‌دهد.

تحویل نهایی

این درس خروجی outputs/skill-gpu-autoscaler-plan.md را تولید می‌کند؛ سندی که با توجه به توپولوژی کلاستر، الگوی بار کاری و SLO، یک طرح مقیاس‌بندی خودکار سه لایه طراحی می‌کند.

تمرین‌ها

  1. اسکریپت code/main.py را اجرا کنید. زیر بار ناگهانی، HPA ساده‌ی مبتنی بر چرخه‌ی کاری چند درخواست را نسبت به HPA مبتنی بر عمق صف از دست می‌دهد؟ منشأ این تفاوت کجاست؟
  2. یک Karpenter NodePool برای کلاستری طراحی کنید که مدل Llama 3.3 70B FP8 را روی H100 SXM5 اجرا می‌کند. مقادیر capacity-type، disruption.consolidationPolicy، consolidateAfter و یک Taint برای دور نگه‌داشتن بارهای کاری غیر از GPU از این نودها را تعیین کنید.
  3. تیم شما گزارش می‌دهد که دیپلوی‌ها در وضعیت Pending گیر کرده‌اند؛ چون «پردازنده‌ها آزادند اما پاد زمان‌بندی نمی‌شود». این موضوع را عیب‌یابی کنید — آیا مشکل از Karpenter است، kube-scheduler یا KAI Scheduler؟ چه متریک‌هایی این موضوع را اثبات می‌کنند؟
  4. یک سیگنال برای مقیاس‌بندی خودکار پادهای تفکیک‌شده‌ی پیش‌پرکنی و سیگنال دیگری برای پادهای رمزگشایی انتخاب کنید. دلایل هر دو انتخاب را بنویسید.
  5. هزینه‌ی مالی ناشی از تله‌ی یکپارچه‌سازی WhenEmptyOrUnderutilized را برای یک سرویس عملیاتی 24x7 که به طور میانگین روزانه 60 بار به خاطر رسیدن P99 TTFT به بیش از 10 ثانیه درخواست‌ها را از دست می‌دهد، محاسبه کنید.

اصطلاحات کلیدی

اصطلاح در گفتار روزمره معنای دقیق فنی
Karpenter «آماده‌ساز نود» مقیاس‌پذیر خودکار نودهای Kubernetes با زمان آماده‌سازی زیر یک دقیقه
Cluster Autoscaler «اسکالر قدیمی» ابزار قدیمی مقیاس‌بندی نودهای Kubernetes؛ کندتر و مبتنی بر گروه‌ها
KAI Scheduler «اسکژولر GPU» اسکژولر ثانویه برای زمان‌بندی هم‌زمان + آگاهی از توپولوژی + صف‌ها
Gang scheduling «همه یا هیچ» زمان‌بندی هم‌زمان N پاد به‌صورت اتمیک، یا به تعویق انداختن تمام آن‌ها
Topology awareness «آگاه به رک» جای‌گذاری پادها بر اساس اتصالات NVLink، اینفینی‌باند و محل رک
DCGM_FI_DEV_GPU_UTIL «استفاده از GPU» متریک چرخه‌ی کاری؛ نه یک سیگنال مقیاس‌بندی برای مدل‌های زبانی
Queue depth «درخواست‌های منتظر» سیگنال مناسب HPA برای مقیاس‌بندی محدود به پیش‌پرکنی
KV cache utilization «فشار حافظه» سیگنال مناسب HPA برای مقیاس‌بندی محدود به رمزگشایی
Consolidation «یکپارچه‌سازی Karpenter» متوقف کردن نود برای مهاجرت به نمونه‌ای ارزان‌تر و مناسب‌تر
WhenEmpty + 1h «یکپارچه‌سازی امن» سیاستی که جاب‌های فعال GPU را از نود بیرون نمی‌اندازد

منابع بیشتر

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسکدام سیگنال که HPA معمولاً به‌طور پیش‌فرض بر اساس آن مقیاس‌بندی می‌کند، در این درس برای سرویس‌دهی مدل‌های مشابه vLLM ناکارآمد نامیده شده است؟
  2. حین درسقابلیت gang scheduling در KAI Scheduler در درجه اول از بروز کدام مشکل جلوگیری می‌کند؟
  3. حین درسچرا سیاست پیش‌فرض Karpenter یعنی consolidationPolicy: WhenEmptyOrUnderutilized برای استخرهای GPU اینفرنس خطرناک است؟
  4. حین درسسرعت Karpenter در بالا آوردن یک نود GPU تقریباً چقدر از Cluster Autoscaler بیشتر است؟
  5. پس از درسبرای پادهای تفکیک‌شده‌ی پیش‌پرکنی (Prefill) و رمزگشایی (Decode)، درس کدام سیگنال‌های مقیاس‌بندی را پیشنهاد می‌کند؟
  6. پس از درسکدام تنظیم اختلال (disruption) در Karpenter توسط درس برای استخر GPU اینفرنس پیشنهاد شده تا از تخلیه کارهای در حال اجرا جلوگیری شود؟

سؤالات متداول

چرا متریک DCGM_FI_DEV_GPU_UTIL برای مقیاس‌بندی HPA در مدل‌های زبانی نامناسب است؟

این متریک چرخه‌ی کاری (Duty cycle) را می‌سنجد و نشان نمی‌دهد چند درخواست در صف هستند؛ پردازنده در لود 10 درخواست یا 100 درخواست به یک اندازه 100% دیده می‌شود و مانع از Scale Up به‌موقع می‌گردد.

زمان‌بندی هم‌زمان (Gang scheduling) در KAI Scheduler چه مشکلی را حل می‌کند؟

این سازوکار از قاعده‌ی همه یا هیچ پیروی می‌کند و مانع از تله‌ی تخصیص ناقص (مانند آماده بودن 7 پردازنده از 8 پردازنده و معطل ماندن آن‌ها تا آماده شدن نود آخر) می‌شود.

سیاست یکپارچه‌سازی امن برای Karpenter روی استخرهای GPU چیست؟

سیاست پیش‌فرض WhenEmptyOrUnderutilized ممکن است جاب‌های فعال را متوقف کند. حالت امن استفاده از WhenEmpty همراه با consolidateAfter: 1h است که فقط نودهای کاملاً خالی را پس از مدتی حذف می‌کند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.