چیتشیت
مقیاسبندی خودکار GPU در Kubernetes
GPU Autoscaling on Kubernetes
نودها با Karpenter، زمانبندی همزمان با KAI Scheduler، رپلیکاها بر اساس عمق صف، مسیریابی آگاه از کش، استوریبوردهای رویداد.
فهرست مطالب
وظایف
کار و کد| وظیفه | کد |
|---|---|
| توقف تخلیه (eviction) جابهای GPU | consolidationPolicy: WhenEmpty |
| تجمیع نودهای خالی پس از یک ساعت | consolidateAfter: 1h |
| اجتناب از رفتار پیشفرض تخلیه | not `WhenEmptyOrUnderutilized` |
| عدم مقیاسبندی بر اساس چرخهی کاری | not `DCGM_FI_DEV_GPU_UTIL` |
| آماده نگهداشتن یک رپلیکا | min_workers=1 |
| بوت نودها با وزنها روی NVMe | snapshot ID in `EC2NodeClass` |
| مسیریابی بر اساس پیشوند کِششده | kv.cache.block_added |
| مقایسهی سه روش مقیاسبندی | simulate(strategy, reqs) |
قطع سرویس ایمن برای استخرهای GPU
کدyaml
# Karpenter NodePool، استخر GPU
disruption:
consolidationPolicy: WhenEmpty # هرگز جاب در حال اجرا را تخلیه نکنید
consolidateAfter: 1h # تجمیع نودهای خالی پس از یک ساعت
سه لایهی مقیاسبندی خودکار
معماریاستراتژیهای مقیاسبندی در main.py
مقایسه| فاکتور | DUTY_CYCLE | QUEUE_DEPTH | KAI_GANG |
|---|---|---|---|
| سیگنال | DCGM_FI_DEV_GPU_UTIL | len(queue) | len(queue) |
| افزایش مقیاس زمانی که | util > TARGET_GPU_UTIL | qd > 5 | qd > 3 |
| گام افزایش | replicas_target += 1 | max(1, qd // 5) | max(2, qd // 3) |
| کاهش مقیاس زمانی که | util < 20 | qd == 0 | qd == 0 |
| نتیجه | درخواستها را دور میریزد | به انباشتگی صف (backlog) واکنش نشان میدهد | از توقفهای تخصیص ناقص جلوگیری میکند |
ثابتهای شبیهساز
پیشفرضها| تنظیم | پیشفرض | نکته |
|---|---|---|
NODE_PROVISION_SEC | 50 | Karpenter حدود 45 تا 60 ثانیه |
CLUSTER_AUTOSCALER_SEC | 110 | مقایسهی کندتر |
MODEL_LOAD_SEC | 45 | وزنهای 70B بهعلاوهی راهاندازی موتور |
HPA_TICK_SEC | 15 | بازه حلقهی کنترل |
TARGET_GPU_UTIL | 70 | هدف چرخهی کاری |
MAX_REPLICAS | 16 | سقف رپلیکا |
CACHE_HIT_MS | 80 | TTFT با پیشوند مقیم در کش |
CACHE_MISS_MS | 800 | TTFT در پیشپرکنی سرد (cold prefill) |
مسیریابی آگاه از کش
گامبهگام- مسیریابپیشوند را هش میکند، برای مثال 512 توکن اول.
- رپلیکاهابا تخصیص و آزادسازی بلوکها، رویدادهای کش کلید-مقدار را منتشر میکنند.
- مسیریاب vLLMرویداد
kv.cache.block_addedرا به نگاشت هش پیشوند به رپلیکا ایندکس میکند. - مسیریابدرخواست را به رپلیکای دارای انطباق ارسال میکند.
- مسیریابدر صورت عدم تطابق، کمترین عمق صف را انتخاب میکند.
- مسیریاب سراسریمقدار RTT را به هزینهی اصابت میافزاید. اگر هزینه از
CACHE_MISS_MSبگذرد، محلی میماند. - محل اقامت داده (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 # خروجی گرفتن از اسنپشات اختصاصی
مراحل استوریبورد
گامبهگام- تجزیه (Parse)تابع
Parse([]byte)(Bundle,error)مقادیرobservedAtو هر دو آرایهی اقلام را بررسی میکند. - گروهبندی (Group)تابع
Group(Bundle)([]Row,error)بیشترین تعداد را بهازای UID هر رویداد نگه میدارد، سپس جمع میزند. - اتصال (Connect)پیمایش ownerReferences به
deployment.kubernetes.io/revision. - خروجی گرفتن (Export)تابع
Export(Bundle)(Pack,error)ساختارschemaVersionنگارش 1 را با پاکسازی دادههای حساس مینویسد. - parsePackتابع
parsePack(text)نگارش، شمارشها و ترتیب زمانی را بررسی میکند. - تایملاین (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را فقط به مسیرهای چت زنده و صوتی اختصاص دهید.