gaogaoGao Kaptan Docsv0.90.x
Örnekler

Qwen3.8 27B (FP8, vLLM)

27B'lik bir modeli tek MIG dilimine FP8 ile sığdırın, vLLM ile sunun ve gerçek gecikme/verim sayılarını ölçün.

27 milyar parametreli bir modeli tek bir MIG dilimine sığdırıp OpenAI uyumlu bir uçtan sunmak, sonra da hızını tahmin etmek yerine ölçmek. Bu sayfadaki bütün sayılar bir H200 NVL kartının 4g.71gb dilimi üzerinde, vLLM'in kendi ölçüm aracıyla alınmıştır.

Neden FP8

Aynı model, üç ayrı biçimde:

BiçimAğırlıklar71 GB dilimdeKalite
bf16~54 GBsığar, ama KV cache'e neredeyse yer kalmazreferans
FP8~30 GBrahat — 32,5 GiB KV cache kaldıbf16'ya çok yakın
GGUF Q4~16 GBen küçükkayıp en fazla

H200 (Hopper) FP8'i donanımda destekler, yani küçültme hızdan çalmaz. Resmi Qwen/Qwen3.8-27B-FP8 deposu ince taneli (blok 128) FP8 kullanır.

MIG'de --tensor-parallel-size 1 olmak zorundadır. MIG, dilimler arasında P2P/NVLink/NCCL'i kapatır; tek bir CUDA süreci yalnızca bir dilim kullanabilir, model iki dilime yayılamaz. FP8'in asıl değeri burada: bf16 tek dilime sıkışırken FP8 rahatça sığıyor.

Pod'u aç

Pod Dağıtımı sayfasından:

  • İmaj: vllm/vllm-openai:latest
  • GPU: MIG, profil 4g.71gb, adet 1
  • Kaynak: 6 vCPU / 28 GB RAM
  • Port: 8000 (dış erişim açık)
  • Kalıcı disk: 80 GB, /data — ağırlıklar buraya insin
  • Ortam değişkeni: HF_HOME=/data/hf
  • İnternet erişimi: açık

Komut:

vllm serve Qwen/Qwen3.8-27B-FP8 \
  --tensor-parallel-size 1 \
  --kv-cache-dtype fp8 \
  --enable-prefix-caching \
  --prefix-match-unit 16 \
  --reasoning-parser qwen3 \
  --host 0.0.0.0 --port 8000 \
  --max-model-len 65536

HF_HOME'u kalıcı diske verin. Ağırlıklar 30 GB ve indirmesi ~45 dakika sürüyor. Konteyner yeniden başlarsa yazılabilir katman imajdan yeniden kurulur; önbellek /data üzerinde değilse her şey baştan iner.

Dilimi doğrula

nvidia-smi -L
GPU 0: NVIDIA H200 NVL (UUID: GPU-ffa8158e-...)
  MIG 4g.71gb     Device  0: (UUID: MIG-a1b2be34-...)

Açılışı izle

vLLM önce çekirdeklerini seçer:

Selected FlashInferFp8DeepGEMMDynamicBlockScaledKernel for Fp8LinearMethod
DeepGEMM PDL enabled · DeepGEMM E8M0 enabled
Using FlashAttention version 3

Sonra ağırlıkları yükler ve en önemli satırı yazar:

Available KV cache memory: 32.5 GiB
GPU KV cache size: 988,865 tokens
Maximum concurrency for 65,536 tokens per request: 15.09x

Bu üç satır size dilimin gerçekte ne verdiğini söyler: ağırlıklardan sonra 32,5 GiB KV cache kalmış, bu da 65K'lık bağlamda 15 eşzamanlı istek demek. Tahmin etmeye gerek yok, vLLM hesabı kendisi yapıyor.

İlk açılış: indirme 43 dk 45 sn, ağırlıkların yüklenmesi 5 dk 24 sn, toplam ~53 dakika. İkinci açılışta indirme yok — ağırlıklar /data'da.

İlk istek

OpenAI uyumlu, yani mevcut istemcileriniz çalışır:

curl -s localhost:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{
  "model": "Qwen/Qwen3.8-27B-FP8",
  "messages": [{"role":"user","content":"Explain what MIG (Multi-Instance GPU) is, in one paragraph."}]
}'

Modelin gerçek cevabı:

MIG (Multi-Instance GPU) is an NVIDIA technology, available on certain data-center GPUs such as A100 and H100, that lets a single physical GPU be partitioned into multiple isolated GPU instances, each with its own dedicated allocation of resources such as memory, memory bandwidth, compute cores, caches, and I/O. (…) making it useful for multi-tenant data centers, cloud environments, and mixed AI/ML workloads.

--reasoning-parser qwen3 verdiğimiz için model düşünme bloklarını ayrı bir reasoning_content alanına koyar. Yukarıdaki cevapta o alan boştu — model doğrudan yanıtladı.

Ham /v1/completions (sohbet değil) ucunu kullanırsanız sohbet şablonu uygulanmaz: model kendi cevabını bitirip istemi tekrar üretebilir. Akıl yürüten modellerde bu beklenen davranıştır; sohbet ucunu kullanın.

Ölç — tahmin etme

vLLM kendi kıyaslama aracıyla gelir, ayrıca bir şey kurmanız gerekmez:

vllm bench serve --model Qwen/Qwen3.8-27B-FP8 \
  --base-url http://localhost:8000 --dataset-name random \
  --num-prompts 40 --random-input-len 512 --random-output-len 256 \
  --percentile-metrics ttft,tpot,itl,e2el --metric-percentiles 25,50,75,99

--max-concurrency ile aynı ölçümü farklı yük altında tekrarlayın. 40 istek, 512 girdi / 256 çıktı token, hepsi başarılı:

mc=1mc=4mc=16sınırsız
İstek/sn0,240,852,344,61
Çıktı tok/sn60,3218,5600,31179,7
Toplam tok/sn180,8655,61800,83539,1
TTFT ortalama65,6 ms226,5 ms529,3 ms1355,3 ms
TTFT P9967,5 ms257,2 ms856,5 ms2128,7 ms
TPOT ortalama16,4 ms17,5 ms20,8 ms28,4 ms
TPOT P9916,4 ms17,7 ms22,4 ms31,9 ms

Tek kullanıcı, akışlı istek: TTFT 35–47 ms, çözme 60,5–61 tok/sn.

Sayıları okumak

Üç ayrı şey ölçülüyor ve karıştırılmamalı:

  • TTFT (time to first token) — "cevap vermeye başladı" hissi. İnsanın algıladığı gecikme.
  • TPOT (time per output token) — sonraki tokenların akış temposu. Metnin okunma hızı.
  • Çıktı tok/sn — sistemin toplam üretimi. Kaç kişiye hizmet verebildiğiniz.

Tablodaki asıl bulgu: eşzamanlılık 1'den 16'ya çıkınca çıktı 10 kat artıyor (60 → 600 tok/sn) ama token temposu yalnızca 16,4 → 20,8 ms bozuluyor. Yani dilimi paylaştırmak neredeyse bedava.

Bedel TTFT'de ödeniyor: 65 ms'den 529 ms'ye çıkıyor. Sohbet arayüzü sunuyorsanız eşzamanlılığı sınırlamak, toplu işlem yapıyorsanız serbest bırakmak doğru olanı.

İşiniz bitince pod'u silin

GPU pod'ları saatlik ücretlendirilir ve dilim siz silene kadar başkasına açılmaz. Ağırlıklar kalıcı diskte kalır; volume'u saklarsanız bir dahaki açılışta indirme olmaz.

"Bu dilim kaç kişiye yeter?"

Bu soru tek sayıyla cevaplanmaz, çünkü aslında üç ayrı soru ve üçü birbirinin aleyhine çalışır. Ölçülen değerlerle:

Eşzamanlı istek1416sınırsız
İlk kelime (TTFT)66 ms227 ms529 ms1.355 ms
Token temposu (TPOT)16,4 ms17,5 ms20,8 ms28,4 ms
Tam cevap (E2EL, 256 token)4,25 sn4,69 sn5,84 sn8,59 sn
Sistem çıktısı60 tok/sn219 tok/sn600 tok/sn1.180 tok/sn
İstek/sn0,240,852,344,61

Tek cümlelik cevap şöyle kurulur:

Tek 4g.71gb diliminde bir kullanıcı ilk kelimeyi 66 ms'de görür ve 256 tokenlık cevabın tamamını 4,2 saniyede alır. Aynı dilim 16 eşzamanlı üretimi kaldırır; o zaman tam cevap 5,8 saniyeye, ilk kelime 0,5 saniyeye çıkar ve sistem toplam 600 token/saniye üretir.

Tablodaki asıl ders: tam cevap süresi 1'den 16 kullanıcıya çıkarken neredeyse sabit kalıyor (4,25 → 5,84 sn) ama sistem çıktısı 10 kat artıyor. Paylaştırmak neredeyse bedava. Bozulan tek şey TTFT — sekiz kat. Kararınızı bu belirler:

  • Sohbet arayüzü: algıyı TTFT belirler → eşzamanlılığı sınırlayın. mc=4 iyi bir denge: 227 ms'de ilk kelime, yine de 219 tok/sn.
  • Toplu iş (özetleme, sınıflandırma, veri işleme): TTFT önemsiz → sınırı kaldırın, 1.180 tok/sn.

Bu sayılar 512 token girdi / 256 token çıktı içindir. İkisi de tabloyu değiştirir:

  • Girdi uzunluğu TTFT'yi doğrudan büyütür — ilk token üretilmeden önce istemin tamamı işlenir (prefill). Ölçtük: TTFT ≈ girdi token sayısı ÷ 7.700, yani 32K'lık bir istemde 66 ms değil ~4,25 saniye. Ayrıntı için aşağıdaki “Uzun istem” bölümü. Tek sayı vermenin en tehlikeli yeri burasıdır.
  • Çıktı uzunluğu tam cevap süresini belirler — 1.000 tokenlık bir cevap tek kullanıcıda yaklaşık 16 saniye (66 ms + 999 × 16,4 ms).
  • "Kaç kullanıcı" ile "kaç eşzamanlı istek" aynı şey değildir. Sohbette kullanıcı ortalama 30 saniyede bir mesaj yazıyorsa, 2,34 istek/sn kabaca 70 eşzamanlı sohbet eder — bu bir hesaptır, ölçüm değil; kendi kullanım deseninizle doğrulayın.

İki dilim: ölçek doğrusal mı?

Bir dilim yetmiyorsa modeli iki dilime bölemezsiniz (MIG'de tensor-parallel-size 1 zorunlu), ama aynı modelin iki bağımsız kopyasını iki dilimde çalıştırıp önlerine bir yük dengeleyici koyabilirsiniz. Soru şu: iki kopya gerçekten iki katı iş yapar mı, yoksa aynı kartı paylaştıkları için birbirlerini yavaşlatırlar mı?

Ölçtük. Aynı kartın iki 4g.71gb dilimi, birbirinin aynı iki kopya (4 CPU / 15 GiB), aynı yük (--max-concurrency 16, 40 istek):

Çıktı tok/sn
Tek kopya (r1, diğeri boşta)597,4
Paralel — r1600,0
Paralel — r2597,1
Toplam1.197,1

Ölçek katsayısı 2,0039 — doğrusal. Gecikmede de kayıp yok: paralel yükte TTFT %0,04 daha düşük, TPOT değişmemiş, uçtan uca süre %0,01 farklı. İki dilim birbirini pratikte hiç etkilemiyor.

İki koşunun %93'ü gerçekten çakıştı (başlangıçlar arasında 0,11 sn fark), 40/40 istek başarılı, iki pod da yeniden başlamadı.

Kopya eklemek ucuz. İkinci kopya, birincinin indirdiği modeli aynı kalıcı diskten okudu — üstelik biraz daha hızlı (306 sn ve 311 sn, birincinin 324 sn'sine karşı). Yani ölçeklerken modeli tekrar indirmeniz gerekmiyor: aynı diski ikinci pod'a bağlamanız yeterli.

Bir de: ikinci kopya ağırlıklarını yüklerken birincinin performansı bozulmadı (yeniden ölçüldü, fark %0,5). Üretim trafiği alırken yeni kopya eklemek güvenli.

Host belleğini yeterli verin. Ağırlıklar VRAM'e gider ama vLLM'in yükleme sırasında host belleğine de ihtiyacı vardır. 4 GiB'lık bir konteyner her denemede aynı yerde (Encoder cache will be initialized... satırından hemen sonra) exitCode 137 ile öldü ve sonsuz yeniden başlama döngüsüne girdi. 15 GiB ile sorunsuz çalıştı.

Teşhis ipucu: pod "running" görünüp hizmet vermiyorsa restart_count'a bakın. Yükleme çubuğunun ilerlemesi aldatıcıdır — her yeniden başlamada baştan başlar.

Tek adres: iki kopyanın önüne yük dengeleyici

İki kopya iki ayrı adres demek; müşteriye tek uç vermek istiyorsanız araya bir yük dengeleyici koyun. Kiracı ağınızda pod'lar birbirini görür (izolasyon yalnızca interneti kapatır, küme içi trafiği değil), yani üçüncü bir pod olarak HAProxy yeterlidir. Her pod'un kendi IP'si olduğu için ikisinin de 8000 dinlemesi sorun değildir.

frontend llm
    bind *:8080
    default_backend vllm_pool

backend vllm_pool
    balance leastconn
    option httpchk GET /health
    http-check expect status 200
    default-server check inter 5s rise 2 fall 3 maxconn 64
    server r1 qwen-r1-svc:8000
    server r2 qwen-r2-svc:8000

Varsayılan ayarlarla kurarsanız üçü de yanlış olur:

  • balance leastconn, round-robin değil. LLM istekleri çok eşitsizdir — 32K'lık bir istem 512'liğin ~64 katı prefill demektir. Round-robin uzun isteği alan kopyaya beslemeye devam eder.
  • timeout server 600s. HAProxy varsayılanı 50 saniyedir; uzun bağlamda tek bir istek 76 saniye sürebiliyor ve üretim ortasında kesilir.
  • option http-no-delay. Token akışı tamponda beklerse TTFT olduğundan kötü görünür.

Ölçüm (aynı kıyaslama, 512 girdi / 256 çıktı):

Doğrudan tek kopyaLB üzerinden, aynı yükLB üzerinden, çift yük
Çıktı tok/sn598,7685,01.248,6
TTFT ortalama543,5 ms358,6 ms512,0 ms
TTFT P99873,8 ms471,1 ms875,3 ms
TPOT20,8 ms18,4 ms21,4 ms

Yük dengeleyicinin bedeli ölçülemedi, çünkü negatif çıktı: aynı yükte LB yolu her metrikte daha hızlı. Trafiğin yarısı ikinci kopyaya düşünce kuyruk azalıyor ve bu kazanç proxy'nin kendi gecikmesini gölgeliyor. Dolayısıyla bu ölçüm hop'un maliyetini ölçmez, üst sınırını koyar: 185 ms'den ucuz.

Çift yükte havuz iki kopyanın toplamını veriyor: 1.248,6 tok/sn, eşleştirilmiş doğrudan tabana (659,1) göre 1,894× — mükemmel 2×'in %94,7'si. leastconn dağılımı da dengeli: 200 isteklik koşuda 99'a 106.

Ölçerken tuzak: ilk denemede 40 istek mc=32 ile yalnızca 10,7 saniye sürdü ve 960 tok/sn çıktı — havuz sınırı sanılabilirdi. Değildi: o kadar kısa bir koşuda rampa ve boşalma baskın olur (anlık tepe 1.606 tok/sn ölçüldü). 200 istekle kararlı duruma çıkınca gerçek sayı göründü. Kısa kıyaslamalar yanıltır.

Yük dengeleyici yetmiyor, kullanıcı başına anahtar, token tavanı ve harcama kaydı da gerekiyorsa aradaki katman HAProxy değil bir LLM kapısıdır. Ölçülmüş kurulumu ve bedeli: LiteLLM: çok kullanıcılı LLM kapısı.

Bundan sonrası: önbellek-farkında yönlendirme

Düz bir yük dengeleyici LLM'in durumlu olduğunu bilmez. Kullanıcılarınız ortak bir sistem istemi paylaşıyorsa, leastconn onları farklı kopyalara dağıtır ve her kopya aynı ön eki sıfırdan hesaplar. Bu sayfadaki kurala göre 32K'lık ortak bir istem her seferinde ~4,25 saniye prefill demektir; önbellekten gelse neredeyse sıfır. (Tek kopya içinde ön ek önbelleğini açmayı aşağıdaki bölüm anlatıyor — ama o yalnızca aynı kopyaya düşen istekleri kurtarır.)

Çözüm, aynı ön eke sahip istekleri aynı kopyaya yönlendiren önbellek-farkında yönlendirmedir (vLLM Router'ın tutarlı hash'lemesi, Ray Serve'in PrefixCacheAffinityRouter'ı, llm-d'nin inference scheduler'ı bunu yapar). vLLM'in kendi belgesi de sınırı açıkça çiziyor: iki basit kopya için standart bir yük dengeleyici yeterlidir; router'ın değeri çok pod'lu mimaride ve durumlu sohbet desenlerinde ortaya çıkar.

Bir sonraki adım olan prefill/decode ayrımı ise MIG'de yapılamaz — dilimler arası P2P kapalı olduğu için ayrı GPU havuzları gerekir.

Uzun istem: TTFT'nin fiyatı

Yukarıdaki bütün sayılar 512 token girdi içindir. İstemi büyütünce ne olduğunu tahmin etmeye gerek yok, ölçtük — aynı araç, aynı çıktı uzunluğu, tek değişken girdi:

512 girdi32.768 girdi
TTFT (tek kullanıcı)65,59 ms4.250,39 ms
Prefill hızı7.806 tok/sn7.709 tok/sn

Girdi 64 kat arttı, TTFT 64,8 kat arttı — prefill hızı ise ikisinde de aynı (fark %1,3). Yani prefill sabit hızlı bir borudur ve şu kural çıkar:

TTFT ≈ girdi token sayısı ÷ 7.700

32K'lık bir istemde ilk kelimeden önce yaklaşık 4,25 saniye sessizlik olur. 8K'da ~1 saniye, 64K'da ~8,5 saniye.

Uzun istemin bedeli peşin ödenir. Tek kullanıcıda token temposu neredeyse değişmiyor (16,40 → 17,78 ms). Yani istem uzun diye metin yavaş akmaz, sadece geç başlar.

Eşzamanlılıkla birlikte ise tablo bozulur:

32K girdimc=1mc=4sınırsız
TTFT4.250 ms7.104 ms37.563 ms
TPOT17,8 ms59,4 ms150,6 ms
Tam cevap (E2EL)8,8 sn22,3 sn76,0 sn
Çıktı tok/sn29,145,851,7

512 tokenlık istemlerde 16 eşzamanlı istek 600 tok/sn veriyordu; 32K'da sınırsız yük 51,7 tok/sn'de kalıyor. mc=4'te P99 ITL 326,7 ms — birinin metni akarken başkasının 32K prefill'i araya girip duraklatıyor.

Darboğaz KV cache değil. Sezgi burada yanıltır: 988.865 tokenlık cache 32K'lık isteklerden 29 tanesini tutar ve 16 istek yerleşikken tepe kullanım %56,3'te kaldı. Ölçümde sıfır preemption görüldü (num_preemptions_total her örneklemede 0,0; logda tek bir tahliye satırı yok). İstekler kuyruğa girdi ama sebep capacity — yani zamanlama kapasitesi, bellek değil.

Pratik sonucu: uzun istem patlamasında daha fazla KV cache almak işe yaramaz. Sınır prefill zamanlamasındadır. Çare, eşzamanlılığı sınırlamak ya da istemi kısaltmaktır.

Bu bölümdeki koşularda 16 istem kullanıldı (temel ölçümde 40'tı) — her istem 64 kat fazla girdi taşıdığı için. İstek başına gecikmeler (TTFT, TPOT, E2EL) iki tabloda doğrudan karşılaştırılabilir; toplam throughput ve "sınırsız" satırı karşılaştırılamaz.

Ön ek önbelleği: bu modelde varsayılan olarak kapalı

Aynı sistem istemini ya da aynı belgeyi tekrar tekrar gönderiyorsanız vLLM prefill'i yeniden hesaplamak zorunda değildir — ortak ön eki önbellekten okuyabilir. Ama bu modelde bunu kendiliğinden yapmaz. Çalışan sunucunun /metrics çıktısı açıkça söylüyordu:

enable_prefix_caching = "False"
vllm:prefix_cache_queries_total = 0.0

--enable-prefix-caching bayrağını açıkça eklemek gerekiyor. Eklediğinizde vLLM Mamba önbelleğini align moduna alır ve bunun deneysel olduğunu söyler.

Bayrakla birlikte ölçüm — aynı ~5.000 tokenlık istem üç kez, ardından ön eki değiştirilmiş bir kontrol isteği:

SüreÖnbellek isabeti
Koşu 1 (soğuk)939,6 ms0 / 5.063
Koşu 2306,4 ms4.704 / 5.063
Koşu 3304,9 ms4.704 / 5.063
Aynı gövde, farklı ön ek849,0 msyeni isabet yok

3,08 kat hızlanma, istek başına 635 ms. Son satır kontrol deneyidir: ön ek değişince isabet sayacı yerinde çakılı kalıyor, yani kazanç "ikinci istek ısınmış olur" etkisi değil, gerçekten ön ek eşleşmesi.

İsabet oranındaki %7'lik boşluk da gürültü değil: bu kopyanın block_size'ı 784 ve 4.704 = 6 × 784. Varsayılan ayarda yalnızca tam bloklar yeniden kullanılır; sondaki 359 tokenlık yarım blok her seferinde yeniden hesaplanır. Aşağıdaki --prefix-match-unit bölümü bu israfı kaldırıyor.

Sebebi FP8 değil — kontrol ettik. Önce "--kv-cache-dtype fp8 kapatıyor olabilir" diye düşündük. Tek değişkeni çevirip vLLM'in yapılandırma katmanını iki kez çalıştırınca hipotez çöktü:

fp8 KV YOK -> enable_prefix_caching=False
fp8 KV VAR -> enable_prefix_caching=False

Sebep modelin kendisi: vLLM bu mimari (GDN doğrusal dikkat + Mamba önbelleği) için ön ek önbelleğini model bazlı varsayılanla kapatıyor. FP8'den vazgeçmenize gerek yok — bayrağı eklemeniz yeterli.

Deneysel olduğunu vLLM'in kendisi söylüyor: açılışta "Mamba katmanları için desteği deneysel" uyarısı düşer, kaynakta ise elle açmanın hatalı çıktı üretebileceği yazar. Bunu ölçtük: aynı istem soğuk, iki kez sıcak ve ön ek önbelleği hiç olmayan ikinci bir kopyada çalıştırıldı — dört cevabın da SHA-256'sı aynı çıktı. Yani bu testte bozulma görülmedi.

Yine de tek bir test genel doğruluk kanıtı değildir. Üretimde açacaksanız kritik çıktıları önbelleksiz bir kopyayla karşılaştırarak doğrulayın.

Kazanç çıktı uzunluğuna göre değişir. Yukarıdaki 3,08 kat, 16 tokenlık cevaplarda ölçüldü — orada süreyi prefill belirler. 180 tokenlık cevaplarda aynı önbellek isabeti 1,67 kata düşer, çünkü zamanın çoğu zaten üretimde geçer. Ön ek önbelleği TTFT'yi iyileştirir, üretim hızını değil.

Hangi bayrak işe yarar, hangisi yaramaz

Ön ek önbelleğini açtıktan sonra akla iki ayar geliyor. Biri boşa kürek, diğeri asıl kazanç.

--prefix-caching-hash-algo: dokunmayın. Varsayılanı zaten sha256, yani en güvenli seçenek; onu tekrar yazmak hiçbir şey değiştirmez. Tek gerçek hamle xxhash'e düşmek olur ve bunun iki sorunu var: vLLM'in kendi belgesi kriptografik olmayan hash'in çok kiracılı ortamda çakışma yoluyla başka kullanıcının verisini sızdırabileceğini yazıyor, üstelik vllm/vllm-openai imajında xxhash paketi kurulu bile değil — pod açılışta ölür. Kazanç tarafı da yok: 784 tokenlık bir bloğun sha256'sı 17,3 µs, aynı bloğun prefill'i 203.636 µs. Yani toplam sürenin on binde 0,85'i.

--prefix-match-unit: asıl kazanç burada. Ön ek isabeti varsayılan olarak yalnızca tam blok sınırında oluşur; blok boyutuna göre her istekte 783 tokene kadar yeniden hesaplanır. Bu bayrak eşleşme granülerliğini düşürür.

Tek değişken farkla iki kopya, aynı ~7.000 tokenlık istem, beşer tekrar:

İsabetYeniden hesaplananSıcak istek (medyan)
--prefix-match-unit 16%99,8 (6.976/6.988)12 token184,2 ms
Varsayılan%89,8 (6.272/6.988)716 token251,5 ms

%26,8 kazanç, 67 ms. Sapma yok (183,9–184,3 ms'ye karşı 251,2–251,7 ms) ve iki kopyanın cevabının SHA-256'sı aynı.

Sayılar tesadüf değil: 6.272 = 8 × 784 ve 6.976 = 436 × 16.

Değeri blok boyutunuza göre seçin, yoksa pod açılmaz. Kural şu: her KV grubunun block_size'ı bu sayıya tam bölünmeli; bölünmezse motor Invalid prefix_match_unit diyip durur.

Tuzak, blok boyutunun sabit olmaması: --kv-cache-dtype fp8 onu ikiye katlıyor (token başına yarı bayt, aynı sayfaya iki kat token). Aynı model, aynı dilim:

block_size
--kv-cache-dtype fp8 ile1.568
fp8 olmadan784

784 = 16 × 49'dur, yani 32'ye bölünmez — "32 koyalım" derseniz fp8'siz kurulumda pod açılmaz. 16 ikisini de böler, üstelik daha incedir. Kendi değerinizi doğrulamak için:

curl -s localhost:8000/metrics | tr ',' '\n' | grep -E 'block_size|prefix_match_unit'

Asıl faydası çok turlu sohbette. Tek seferlik istemde 67 ms kulağa mütevazı gelir. Ama sohbet her turda birkaç yüz token büyür ve ön ek (sistem istemi + geçmiş) hep aynı kalır. Varsayılan granülerlikte her turda artan kısım yeniden hesaplanır ve yeni bir blok dolana kadar bu israf büyüyerek tekrarlar. 16 ile kayıp hiçbir zaman 15 tokeni geçmez.

MIG'de GPU okumaları — hangisi çalışır

Bu, MIG'e özgü ve şaşırtıcı: sorgu biçimi çalışmaz, tablo çalışır.

nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv
[N/A], [Insufficient Permissions], [Insufficient Permissions]

Ama düz nvidia-smi çıktısındaki MIG tablosu dilimin belleğini verir:

30241MiB / 71424MiB     (ağırlıklar yüklendi)
65799MiB / 71424MiB     (KV cache dolarken)

Yani "MIG'de bellek görünmez" doğru değil — --query-gpu görmez, MIG tablosu görür. İzleme kurarken buna dikkat edin.

Sıcaklık ve güç okunur ve — sezginin aksine — kartın geneline değil, sizin kendi GPU örneğinize aittir. İki dilimden aynı saniyede örnekleme yaptık: boştaki konteyner 129,2 W / 55 °C okurken çalışan 401,3 W / 68 °C okuyordu. Yani bu değerlerle kartın toplam yükünü çıkaramazsınız; board toplamı için nvidia-smi'yi host üzerinde çalışormalısınız.

Ölçülen dilim değerleri: boşta 129,2 W / 55 °C, tek kopya yük altında 401,3 W / 68 °C.

Ölçülen süreler

AdımSüre
vllm/vllm-openai imajı (düğümde önbellekliyse)21 sn
FP8 ağırlıklarının inmesi (30,89 GB)43 dk 45 sn
Ağırlıkların GPU'ya yüklenmesi5 dk 24 sn
Toplam: pod açılışından ilk isteğe~53 dk

Sık karşılaşılan hatalar

BelirtiSebep
Pod açılırken öldürülüyorİmaj düğümde yok ve çekimi 30 dakikayı aşıyor; imajı önceden dağıtın
Yeniden başlayınca model tekrar iniyorHF_HOME kalıcı diskte değil
tensor-parallel-size 2 çalışmıyorMIG'de mümkün değil — dilimler arası P2P kapalı
TTFT 3 ms görünüyorcurl -w time_starttransfer akışta başlık flush'ını ölçer, ilk tokenı değil
bf16 sürüm sığmıyor27B bf16 ≈ 54 GB; 71 GB dilimde KV cache'e yer kalmaz, FP8 kullanın
CPU değiştirdim ama pod yeniden başladıİstekte memory_limit de gönderilmiş — değeri aynı olsa bile bellek boyutlandırması sayılır ve konteyneri yeniden başlatır. Yalnız cpu_limit gönderin
Uzun istemde ilk kelime çok geç geliyorNormal — prefill sabit hızlı: TTFT ≈ girdi ÷ 7.700 tok/sn
Invalid prefix_match_unit ile açılmıyorDeğer block_size'a bölünmüyor; fp8 bloğu 1.568, fp8'siz 784 yapar — 16 ikisini de böler
Aynı istemi tekrar gönderince hiç hızlanmıyorÖn ek önbelleği bu modelde varsayılan kapalı; --enable-prefix-caching ekleyin
Uzun istem yükünde her şey yavaşladıDarboğaz KV cache değil, prefill zamanlaması; eşzamanlılığı sınırlayın
Bu sayfa yardımcı oldu mu?

On this page