localaiforum
Anmelden
Guide › Betrieb & Serving

Batching & mehrere Nutzer

Eine Anfrage nach der anderen ist, wie jede Desktop-Sitzung beginnt — und es verschwendet eine GPU. Das ganze Spiel des Servings ist Batching: einen Durchlauf durch die Gewichte viele Anfragen zugleich bedienen zu lassen. Diese Seite deckt ab, warum das funktioniert, was Continuous Batching und Paged Attention wirklich sind, wann Sie eine echte Serving-Engine brauchen und wie man das Ding bemisst.

Warum serielle Bedienung die GPU verschwendet

Rufen Sie sich die Geschwindigkeitsformel in Erinnerung: Jedes dekodierte Token liest im Wesentlichen alle aktiven Gewichte einmal (Geschwindigkeit). Bedient die GPU einen Stream, tut sie diese ganze Lesung für ein einziges Token eines einzigen Nutzers. Batchen Sie nun acht Streams in denselben Forward-Pass: Die Gewichte werden einmal gelesen und für acht Sequenzen genutzt — die zusätzliche Arithmetik ist nahezu gratis, weil Decode bandbreiten- und nicht rechenlimitiert ist. Die Geschwindigkeit pro Stream sinkt kaum, während der Gesamtdurchsatz fast linear steigt, bis Sie Bandbreite oder KV-Speicher sättigen. Diese eine Tatsache ist die gesamte Ökonomie des lokalen Servings.

Statisches vs. Continuous Batching

Die naive Version — statisches Batching — gruppiert Anfragen, die zusammen eintrafen, und fährt den Batch, bis jedes Mitglied fertig ist. Es funktioniert, schlecht:

Statisches Batching Continuous Batching
Batch gebildet einmal, wenn sich die Gruppe versammelt bei jedem Decode-Schritt neu bewertet
Beitreten während des Laufs Nein — wartet auf den nächsten Batch Ja, Slots füllen sich, sobald Anfragen eintreffen
Kurze Anfrage im Batch langer blockiert, bis die längste fertig ist endet sofort und gibt ihren Slot frei
Tail-Latenz schlecht (Head-of-Line-Blocking) gut

Continuous (Iterations-Level-)Batching — der Standard in vLLM und SGLang — ist der Grund, warum diese Engines unter echtem Traffic standhalten, während naive Server kollabieren.

Paged Attention: die KV-Fragmentierung reparieren

Jede aktive Anfrage braucht KV-Cache-Speicher (siehe KV-Cache). Der alte Ansatz reservierte den maximalen Kontext jeder Anfrage vorab — ein Chat mit 2k Tokens hielt also womöglich einen reservierten 32k-Block, verschlossen und für niemanden sonst nutzbar. Das meiste des KV-Pools saß brach. Paged Attention speichert KV in fest großen, bei Bedarf allocierten Blöcken, so wie ein OS Speicher seitenweise verwaltet: Die Verschwendung fällt von der Mehrheit (die vLLM-Autoren berichteten in ihrem Paper von 60–80%) auf wenige Prozent, mehrfach mehr gleichzeitige Sequenzen passen hinein, und der Durchsatz folgt. Dieselbe Idee, heute Standard über alle Serving-Engines.

Kosten für Sie: nichts Nutzerseitiges — es ist eine Allocator-Änderung; Sie sehen einfach höhere gleichzeitige Kapazität auf derselben GPU.

Wann Sie eine echte Serving-Engine brauchen

Arbeitslast Engine
Sie plus Haushalt, ein paar sequenzielle Chats Ollama / LM Studio — schon fein
Ein paar Entwickler, nebenbei parallel llama-server mit parallelen Slots oder Ollama-Parallel-Env
Produkt-Traffic, Team-Chat, echte Nutzer vLLM oder SGLang
Agenten-Flotten mit langen geteilten System-Prompts SGLang (Präfix-Caching) oder vLLM

Die Spieleecke dieses Forums ist das kanonische Beispiel der letzten Zeile: Schach- und Janggi-Partien fahren mehrere Agenten, von denen jeder etwa jede Sekunde einen Zug anfragt — kleine Prompts, viele Streams, geteilte System-Prompts. Das ist exakt die Arbeitslast, die eine Serving-Engine mit Batching will, nicht ollama run in einer Schleife (siehe Agenten).

Durchsatz vs. Latenz

Jeder Regler tauscht das eine gegen das andere: Größere Batches heben die Gesamt-tok/s, während sie die Geschwindigkeit pro Stream leicht senken, und Warteschlangen heben das TTFT unter Last. Ein Coding-Assistent für eine Person will Parallelität auf 1–2 gedeckelt, damit der Stream des Menschen nie wartet. Ein Chat-Dienst für dreißig Leute will vollgepackte Batches. Entscheiden Sie, welcher Sie sind, bevor Sie tunen (siehe Serving für TTFT vs. Decode als getrennte Messungen).

Das Nächste zu einem Gratisessen ist Präfix-Caching (SGLang): Wiederholte lange Prompts werden zu nahe null Prefill, und das ist die meisten Agenten-Workloads.

Praktische Regler

# llama.cpp: parallele Decode-Slots (Kontext wird auf Slots aufgeteilt)
llama-server -m model.gguf -c 32768 -np 4

# Ollama: parallele Anfragen pro Model (Dienst nach dem Setzen neu starten)
export OLLAMA_NUM_PARALLEL=4

# vLLM: die beiden, die zählen
vllm serve model --max-num-seqs 32 --gpu-memory-utilization 0.90

Warteschlangen entstehen stromaufwärts von all diesen: Wenn jeder Slot beschäftigt ist, warten neue Anfragen. Beobachten Sie Warteschlangentiefe und TTFT, nicht Bauchgefühl.

Setzen Sie auch stromaufwärts Grenzen: Ein Reverse Proxy mit Verbindungsgrenze scheitert schnell und ehrlich, wo eine tiefe Warteschlange langsam und mysteriös scheitert.

Kapazitätsplanung, ungefähr

Was eine Anfrage über die Gewichte hinaus kostet, ist KV-Cache, pro Token, für ihren ganzen Kontext:

KV bytes/token ≈ 2 × layers × kv_heads × head_dim × bytes_per_value

Durchgerechnet, typisches dichtes 8B-Modell (32 Layer, 8 KV-Heads, Head-Dim 128, fp16-Werte):
2 × 32 × 8 × 128 × 2 B ≈ 131 KB pro Token → eine 2k-Token-Konversation ≈ 256 MiB KV → zehn solcher Chats ≈ 2,5 GB obendrauf auf die ~5 GB Gewichte.

(Die 2 ist K und V; siehe KV-Cache). Langkontext-Agenten sind deshalb pro Anfrage weit teurer als Chat. Grobe Komforttabelle, stark abgesichert — Chat-lange Kontexte, nur Größenordnung:

GPU Model Grob gleichzeitige leichte Chats
8 GB 7–8B Q4 1–3
24 GB 8B Q4 ~10–30
24 GB 32B Q4 ~3–8
48 GB 70B Q4 ~5–15

Messen Sie mit Ihren echten Prompts: Die Kontextlänge bewegt diese Zahlen mehr als jede andere Variable.

Signale, dass Sie gesättigt sind

  • TTFT klettert im Laufe des Tages von Millisekunden zu Sekunden.
  • Warteschlangentiefe dauerhaft über null; Anfragen warten vor dem ersten Token.
  • tok/s pro Stream sacken ab, wenn Batches sich vollpacken.
  • vLLM-Logs zeigen Preemption oder KV-Neuberechnung — Speicherdruck, nicht Modell-Trägheit.

Bei jedem davon: Kontext deckeln, KV-Cache quantisieren oder GPU ergänzen — in dieser Reihenfolge der Billigkeit —, bevor Ihre Nutzer laut klagen.

Grafen Sie TTFT und Warteschlangentiefe über einen Tag — ein stetiger Anstieg bedeutet Kapazität, ein Sägezahn bedeutet Ausbrüche, die Sie mit einer Warteschlange schlucken können.

Mieten vs. Kaufen, skizziert

Zum Zeitpunkt dieses Textes läuft eine gemietete GPU der 24-GB-Klasse grob $0.50–2 pro Stunde, und eine gebrauchte 24-GB-Karte kostet ein paar hundert Dollar — Break-even irgendwo um 300–1.000 Stunden tatsächlicher Generierung. Lokal gewinnt bei Privatsphäre, Latenz und ohne Rate-Limits (die Rahmung in Warum lokal); Mieten gewinnt bei burstigem Bedarf und Modellen der 80-GB-Klasse, die keine Consumer-Karte hält (siehe VRAM-Mathematik dafür, was wohin passt). Die meisten Leute überschätzen ihre Stunden — instrumentieren Sie eine echte Woche, bevor Sie entscheiden.

Verwandt: Geschwindigkeit · KV-Cache · Einen Endpunkt serven · VRAM-Mathematik