Två boxar i DGX Spark-klass, en modell: en kopia på varje maskin slår split
Drift
Under sju veckor körde vår lokala språkmodell splittrad över två NVIDIA GB10-maskiner med tensor parallelism. Den 22 oktober ersatte vi det med en fullständig kopia av modellen på varje maskin och en least-connection-proxy framför. Genomströmningen gick från cirka 180 till 210 tokens per sekund, och antingen maskin kan nu starta om utan att ta bort modellen.
Varför vi splittrade den
Varje maskin har 128 GB minne som CPU:n och GPU:n delar. I september fick modellen plats på en maskin, men dess cache knappt: den vLLM-build vi använde kunde inte hålla denna modells KV-cache i FP8, så cachen var i BF16, och en maskin hade plats för 499 110 tokens av den. Det är färre än två förfrågningar vid modellens fulla kontext på 262 144 tokens. Splittrad över båda maskinerna med tensor parallelism över deras direkta nätverkslänk växte cachen till mer än tre miljoner tokens. Vi splittrade modellen för plats, inte för hastighet.
Vad som ändrats
En nyare 4-bitars build av samma modell (NVFP4, gjord med kvantiseringsmedveten distillation) tar cirka 71 GiB minne, och en community-vLLM-build för GB10 (eugr/spark-vllm-b12x) kör dess cache i FP8. Nu rymmer en maskin hela modellen och en cache på 0,76 till 1,08 miljoner tokens, plats för 2,9 till 4,1 förfrågningar vid full kontext, beroende på hur mycket minne maskinen tilldelas. Båda kopierna använder modellens egen spekulativa avkodning (MTP, fyra utkasttokens). Innan vi bytte körde vi vårt verktygsanropstest på den nya builden: den fick 86, den build den ersatte fick 75.
Vad vi mätte
| Splittrad över två maskiner | En kopia på varje maskin | |
|---|---|---|
| KV-cache | mer än 3 miljoner tokens | 0,76 och 1,08 miljoner tokens |
| Förfrågningar vid full kontext | cirka 12 | 2,9 och 4,1 |
| Genomströmning under vår belastning | cirka 180 tokens/s | 210 tokens/s (111 + 99) |
| Start | cirka 20 minuter | 5 till 13 minuter per kopia |
| En maskin startar om | modellen är nere | den andra kopian serverar |
En kopia för sig, efter antalet samtidiga förfrågningar: med korta prompter gav 1 förfrågan 36 tokens per sekund, 4 gav 82, 8 gav 109 och 16 gav 150. Med vår e-postagents längre prompter gav 4 förfrågningar 81, 8 gav 113 och 16 bara 87: fler än åtta sådana förfrågningar gjorde det långsammare.
Under en eftermiddag tog den ena kopian som mest 12 samtidiga förfrågningar och den andra 8. Den första producerade 91 till 93 tokens per sekund och klarade 26 till 27 förfrågningar per minut; den andra 81 till 83 tokens per sekund och 22 förfrågningar per minut. Båda tar nu 12.
Vad vi offrade
Utrymme. Den uppdelade modellen hade en cache på mer än tre miljoner tokens; kopiorna har två mindre, och en förfrågan kan bara använda cachen hos den kopia som betjänar den. Våra agenter skickar många korta och medellånga förfrågningar, och för dem betydde genomströmning mer. Om du betjänar några mycket långa kontexter samtidigt kan uppdelning fortfarande vara det bättre valet. Vi behöll den uppdelade konfigurationen, och att byta tillbaka är ett skript.
Vad som gick fel under bytet
- Elva minuter utan modell, sedan 30 sekunder med 502. Den uppdelade modellen måste stoppas innan en kopia kunde laddas på samma maskiner, så våra agenter väntade i cirka elva minuter. När den första kopian startade svarade proxyn med ”502 no live upstreams” i cirka 30 sekunder till: den hade markerat backends som felaktiga medan de var nere (max_fails=3, fail_timeout=30s) och försökte inte igen förrän tiden löpte ut.
- En klient som hoppade över proxyn. Ett av våra batchjobb hade den första maskinens adress i sin konfiguration, så hela dess last gick till en kopia medan den andra hade kapacitet över. Varje klient går nu via proxyn; maskinernas egna adresser används bara för hälsokontroller.
- Mätvärden som hoppade. Vår övervakning av genomströmning läste vLLM:s /metrics via proxyn. Med två backends kom på varandra följande läsningar från olika kopior, räknarna hoppade fram och tillbaka, och övervakningen rapporterade modellen som svältande. Den läser nu varje kopia direkt och summerar dem.
- En gammal bevakningsprocess som hade stoppat den nya kopian. Den uppdelade konfigurationen hade en bevakningsprocess som startade om sin tjänst när modellen slutade svara. Den nya tjänsten deklarerar Conflicts= med den gamla, så att omstarten hade stoppat den nya kopian. Den måste stängas av med
systemctl disable --now, inte bara stoppas, eftersom vårt driftlager startar om enheter som är aktiverade men inte kör. - Minne på maskinen som gör annat arbete. En maskin kör också våra databaser och webbplatsbyggen. Med vLLM:s gpu-memory-utilization på 0,78 återstod bara 5 GiB för allt annat, så vi sänkte det till 0,74 och startade om bara den kopian medan den andra bar lasten. På dessa maskiner tas den andel du ger vLLM ut ur samma minne som allt annat.
Om du har två av dessa maskiner
- Om modellen och cachen du behöver får plats på en maskin, kör en kopia på varje bakom en proxy med minst anslutning. Dela bara upp modellen när en maskin inte rymmer cachen du behöver.
- Peka alla klienter mot proxyn, inklusive batchjobb och gamla konfigurationer.
- Läs in mätvärden från varje kopia direkt.
- Ge varje maskin sin egen minnesandel, beroende på vad som mer körs på den.
- Ställ in hur många förfrågningar en kopia betjänar samtidigt med din egen trafik: för vår blandning slog 12 ut 8.
- Räkna med att bytet tar bort modellen under den tid det tar för en kopia att starta, och planera för det.
Factory Floor levererar proxyn och startkonfigurationerna för en eller två maskiner, hälsokontrollen och verktygsanvändningstestet vi kör innan vi byter modeller, med bevakningsprocesser och minnessäkerhetskontroller för resten av maskinen.