· kaynak dev.to (home feed)
KV cache limitlerinin sabitlenmesi GPUStack GPU filolarındaki vLLM OOM çökmelerini durduruyor
Üretim ortamına dair bir yazı, GPUStack'in VRAM tahmininin sequence başına KV büyümesini görmezden geldiğini ve bağlam uzunluğu, bellek kullanımı ile eşzamanlılık sabitlenene kadar 70B'lik bir vLLM dağıtımında tekrarlayan OOM'lara yol açtığını gösteriyor.
Ne yaşandı
Karışık RTX A6000 ve RTX 4090 kartlardan oluşan dört düğümlü, kendi veri merkezinde barındırılan bir çıkarım (inference) filosu işleten bir ekip, iki ay önce elle yazılmış Docker başlatma betiklerinden GPUStack'e geçti. dev.to'daki bir yazıya göre platform vaat edildiği gibi çalışıyor: tek bir kontrol düzlemi, uygun GPU'larda modelleri zamanlıyor, her dağıtım için vLLM, SGLang veya llama-box gibi bir serving backend başlatıyor ve OpenAI uyumlu bir endpoint sunuyor. Ancak ekip, platformun yerleştirme mantığının öngörmediği bir arıza moduna denk geldi ve bu onlara bir hafta sonuna mal oldu.
Varsayılan tahmin nerede tıkanıyor
GPUStack, bir modelin nereye yerleşeceğine ağırlık boyutu ve belirtilen bağlam uzunluğundan türetilen bir VRAM tahminiyle karar veriyor. Yazarın da belirttiği gibi, bu tahminin aktivasyon belleği tepelerine, CUDA graph yakalamasına veya kullanıcıların gönderdiği prompt'ların gerçek dağılımına dair hiçbir görünürlüğü yok. Bunu bir zamanlama sezgiseli değil de runtime garantisi olarak ele almak kazaya yol açtı.
Arıza, tensör paralelliği (tensor parallelism) 4'e ayarlanmış dört karta bölünen ve bağlam uzunluğu varsayılan değerinde bırakılmış, bf16'daki 70B parametreli bir modelle ortaya çıktı. Dağıtım, 6k-8k token'lık isteklerin geldiği gerçek trafik gelene kadar sağlıklı görünüyordu; o noktada worker'lar birer birer bellek yetersizliği (out-of-memory) hatalarıyla çöktü ve yeniden başlatıldı. Bu bir zamanlayıcı kararsızlığına benziyordu ama sonuçta bir bellek muhasebesi sorunuydu.
dev.to yazısı hesabı adım adım anlatıyor: 80 katman, 8 KV head, 128 boyutlu head boyu, K ve V tensörleri ve değer başına 2 bayt ile Llama-3.3-70B, token başına yaklaşık 320 KB KV cache tüketiyor. 32k bağlamda bu, kart başına kabaca 35 GB ağırlığın üzerine binen, sequence başına yaklaşık 10.7 GB KV cache demek. İki eşzamanlı uzun sequence kartı tüketiyor. Tahminci, bağlamı sabit bir bütçe olarak ele almıştı; oysa doğru hesap, sequence başına ayrılan miktarın eşzamanlılıkla çarpımıydı.
Sağlamlaştırılmış yapılandırma
Yazara göre çözüm gösterişsiz: varsayılanları kabul etmek yerine değerleri sabitlemek. Ekip, prompt p99'larını 11k olarak ölçtükten sonra max-model-len'i 16384'e ayarlayıp havuzu ikiye katlamadan KV tavanını sınırladı. gpu-memory-utilization'ı 0.88'e ayarladılar; çünkü 0.92'nin aynı ağırlıklarla çöktüğünü görmüşlerdi — TP=4 altında graph capture, insanların genelde varsaydığı boşluğa sığmıyor. max-num-seqs'yi 32'de sınırladılar ki KV havuzu aşırı abone edilemesin; chunked prefill'i etkinleştirdiler ve swap-space'i bilinçli olarak sıfıra ayarladılar; çünkü host tarafındaki takas, dürüst bir çökmeyi, sabah 2'de ağ arızası gibi görünen yaklaşık 40 katlık bir gecikme bozulmasına dönüştürüyor. Ayrıca KV cache'i fp8'e geçirip ayak izini, eval alt kümelerlerinde ölçülebilir bir gerileme olmadan yarıya indirdiler; yine de uzun bağlamlı erişimin (retrieval) sohbete göre daha çok bozulduğunu ve önce test edilmesi gerektiği uyarısında bulundular.
Tensör paralelliğinin mümkün olmadığı heterojen bir düğümde GPUStack, llama-box'a katman boşaltımıyla (layer offload) geri düştü. Oradaki eşdeğer disiplin, 48 GB'lık bir kartta GPU'da tutulan katmanları 80'in 60'ında sınırlamaktı; 80'inin tamamını istemek, yüklenen ama ilk 4k token'lık prompt'ta ölen bir model üretiyordu.
Yavaş bozulmayı yakalamak
İkinci, daha sinsi bir sorun ortaya çıktı: 36 saat boyunca verimlilik (throughput) yaklaşık %18 düştü, buna karşın GPU kullanımı sabit kaldı. Yazarın teşhis yöntemi, ilk token'a kadar geçen sürenin (time-to-first-token) yüzdeliklerini ve worker'ın yerleşik belleğini birlikte ölçmekti. RSS'deki tekdüze artışın p95 gecikmesiyle birlikte izlemesi, KV havuzu büyümesini ve blok parçalanmasını gösteriyor; yükselen p95 ve sabit RSS ise yerleştirme ya da önleme (preemption) sorununa işaret ediyor. Filolarında ilki vardı ve bu, eşzamanlılık sınırı ile sabit bir cron programı yerine RSS-eğimi eşiğine dayalı worker geri dönüşümüyle çözüldü.
Bir ikilem hâlâ çözümsüz: kısa prompt'lu, yüksek eşzamanlılıklı sohbet ile 30k token'lık prompt'lar gönderen gecelik bir toplu işi aynı endpoint'ten sunmak. İki dağıtıma bölmek yerleşik ağırlıkları ikiye katlıyor; havuzlar arasında istek başına yönlendirme ise ekibin hata ayıklamaya bütçe ayırmadığı ek bir zıplama ekliyor.
Neden önemli
GPUStack gibi orkestrasyon katmanları büyük modelleri mevcut donanımda dağıtmayı kolaylaştırdıkça, yerleştirme tahmini ile gerçek runtime bellek davranışı arasındaki boşluk operasyonel risk haline geliyor. KV cache, sequence uzunluğu çarpı eşzamanlılıkla ölçekleniyor; varsayılan ayarlar bunu ne ölçüyor ne de sınırlıyor. Pratik ders GPUStack'in ötesine genelleniyor: prompt p99'unuzu ölçün; bağlam uzunluğunu, bellek kullanımını ve eşzamanlılığı sabitleyin; host takasını kapatın; ve yavaş bir bozulma sabah 2'nin kazasına dönüşmeden önce parçalanmayı önlemeden ayırt etmek için TTFT'yi RSS ile birlikte izleyin.
- #vllm
- #gpustack
- #llm-inference
- #gpu-memory
- #kv-cache