Vår hälsokontroll startade om en frisk modellserver åtta gånger på en dag
Drift
Den 22 juli startade en bevakningsprocess om vår lokala modellserver åtta gånger. Inte en enda av dessa omstarter hade en krasch bakom sig. Kontrollen som skulle hålla modellen igång var det som sänkte den.
Vad som hände
Modellservern körde vLLM på en NVIDIA GB10-maskin och producerade cirka 8 tokens per sekund för en enskild förfrågan. Var femte minut skickade en bevakningsprocess en riktig chattförfrågan och väntade i upp till 45 sekunder på svaret. Fem misslyckade kontroller i rad innebar att servern hängde sig, och bevakningsprocessen startade om den. En omstart tog modellen ur drift i flera minuter medan cirka 19 GB av vikterna laddades in igen.
Den dagen höll ett batchjobb två till fyra förfrågningar upptagna på servern i flera minuter åt gången. Bevakningsprocessens förfrågan fick vänta i kön bakom dem, tog slut på tid och räknades som ett misslyckande. Fem sådana kontroller senare startades en frisk server om. Vi hade en "busy"-flaggfil som bevakningsprocessen respekterade, men batchjobbet satte aldrig den.
Hur en falsk omstart ledde till nästa
Varje omstart misslyckade med de pågående förfrågningarna med ett 500-fel ("cannot schedule new futures after shutdown"). En andra bevakningsprocess räknade 500-fel och startade om servern när det blev för många, och ju fler fel den såg, desto snabbare agerade den. Så varje falsk omstart fick nästa att komma tidigare. Sammanlagt kunde fyra separata bevakningsprocesser starta om den servern, på 5, 10, 15 och 30 minuters timers.
Regeln vi drog från det
En hälsokontroll får inte använda det den bevakar. En modellserverns knappa resurs är dess platser för pågående förfrågningar. En kontroll som tar en av dessa platser, eller väntar på en, är en del av den belastning den ska bedöma. Kontrollera billigt, och starta om bara när du kan visa att servern har fastnat.
Kontrollen som ersatte den
vLLM publicerar sina egna räknare på /metrics. Den nya kontrollen läser dem först:
- Pågående förfrågningar och motorn gör framsteg: frisk och upptagen. Ingen testförfrågan skickas.
- Pågående förfrågningar och inga framsteg mellan två läsningar: fastnad. Detta är fallet som fortfarande startar om.
- Inget pågår: inaktiv. Först då ber kontrollen om ett kort svar, vilket en inaktiv motor ger direkt.
Den första versionen räknade genererade tokens som framsteg. Den klarade åtta tester, och vid sin första livekörning fann den servern upptagen och frisk: 2 pågående förfrågningar, 107 nya tokens mellan de två läsningarna.
Vad vi har ändrat sedan dess
- Steg i motorn, inte utdatatokens. Medan vLLM läser en lång prompt producerar den inga utdatatokens ett tag men tar fortfarande steg. Att räkna steg (antalet vllm:iteration_tokens_total) gör att en lång prompt inte ser ut som en fastnat server.
- Tvänta innan ”fastnat”, så att en kort paus inte räknas som ett fel.
- En omstart mellan de två avläsningarna fångas upp av processens starttid i samma mätvärden; kontrollen ber då om ett svar i stället för att jämföra räknare från två olika processer.
- En proxy kontrolleras endast via /models. Bakom en proxy med minst antal anslutningar kan varje avläsning av /metrics komma från en annan backend, som vi upptäckte när vi körde en kopia av modellen på var sin av två maskiner. Backenderna kontrolleras direkt.
Skillnaden är lätt att se. När vi skrev den här notisen körde båda våra modellservrar 12 förfrågningar vardera, deras gräns. En testförfrågan hade fått vänta i kön. Den nya kontrollen rapporterade båda som upptagna och friska, med 126 respektive 101 tokens per sekund, utan att skicka någon.
Factory Floor 1.0.2 levererar denna kontroll som models/llm-health.py, med tester för inaktiva, upptagna, fastnade och omstartade servrar, en server utan mätvärden, en proxy och en död backend.