LLM Serving with SGLang
Start, query, size, measure and fix an SGLang server. Pinned to SGLang 0.5.22.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
Tasks#
| Task | Code |
|---|---|
| Start a server | sglang serve --model-path <model> --port 30000 |
| Native request | POST / |
| OpenAI-style request | POST / |
| Readiness probe | GET / |
| Read metrics | GET / |
| Benchmark at a fixed concurrency cap | --max-concurrency 8 |
| Benchmark at a fixed request rate | --request-rate <rps> |
| Stop with a drain | docker stop <container> |
From sglang-101 capture: server-default.command.txt, sglang-101 capture: one_request.py, sglang-101 capture: run.py, sglang-101 §5.1, sglang-101 §5.2, sglang-101 §7.1
Start the server (terminal 1)#
sglang serve --model-path <model> \weights to load --port 30000 \HTTP port --enable-cache-report \cached_tokens in usage --enable-metrics \turns on /metrics --mem-fraction-static 0.4weights plus KV pool shareFrom sglang-101 capture: server-default.command.txt, sglang-101 §R1, sglang-101 §2.1, sglang-101 §3.2
Benchmark it (terminal 2)#
python -m sglang.benchmark.serving --backend sglang \ --port 30000 --dataset-name random \ --random-input-len 512 --random-output-len 128 \ --random-range-ratio 1.0 \default 0.0 halves prompts --num-prompts 32 --max-concurrency 8255.63 tok/s on the captureFrom sglang-101 capture: run.py, sglang-101 §5.1, sglang-101 §R1, sglang-101 capture: bench-random-c8.txt, sglang-101 capture: bench-random-c32.txt
Key flags#
| Command | What it does |
|---|---|
--mem-fraction-static <f> | Memory share for weights plus KV pool |
--max-total-tokens <n> | Fixes the KV pool size in tokens |
--max-running-requests <n> | Caps decoding requests. Set it at the knee |
--chunked-prefill-size <n> | Largest prompt piece in one step |
--schedule-policy lpm | Longest prefix match order |
--schedule-conservativeness 1.3 | Higher forecast, fewer retractions |
--disable-radix-cache | No prefix reuse. Only to measure |
--tp-size <n> | Splits each layer over n GPUs |
From sglang-101 §R1, sglang-101 §2.2, sglang-101 §2.3, sglang-101 §3.2, sglang-101 §6.1, sglang-101 §5.1
Three processes#
Key metrics#
- sglang:time_to_first_token_seconds
- histogram. Alert on p99 over 5 min.
- sglang:inter_token_latency_seconds
- histogram. Shows stream stutter.
- sglang:queue_time_seconds
- histogram. Wait before first prefill.
- sglang:num_queue_reqs
- gauge. Above 0 for minutes means past the knee.
- sglang:token_usage
- gauge. Near 1.0 means the pool is full.
- sglang:num_retracted_reqs
- gauge. Alert above 0.
- sglang:prefill_effective_tokens_total
- counter. Windowed hit rate from its modes.
- sglang:cache_hit_rate
- gauge. Last log interval only.
Log lines to read#
| Command | What it does |
|---|---|
bytes_per_slot= | KV bytes per token, pool slots |
max_total_num_tokens= | Pool size SGLang computed |
max_running_requests= | Computed request cap |
#new-token: 3, | New plus cached is the prompt |
#running-req: 5, | Admission holds requests back |
KV cache pool is full. Retract requests. | Retraction. A performance alarm |
crashed with exit code -15 | Our SIGTERM, not a fault |
Insufficient Memory | Out of memory outside the pool |
From sglang-101 capture: server-default.log, sglang-101 capture: server-small-pool.log, sglang-101 capture: oom-exploratory.log, sglang-101 §2.1, sglang-101 §2.3
One request, end to end#
From sglang-101 §2.1, sglang-101 §2.2, sglang-101 §2.3, sglang-101 §3.3
Defaults in the code#
| Setting | Default | Note |
|---|---|---|
--mem-fraction-static | None | Derived at startup. Kit sets 0.4 |
--max-running-requests | None | Derived from pool and context |
--chunked-prefill-size | None | Derived from GPU memory |
--schedule-conservativeness | 1.0 | Raise it on retractions |
--schedule-policy | fcfs | Try lpm for long shared prefixes |
--enable-cache-report | False | Set it always |
--enable-metrics | None | Resolves to off |
--watchdog-timeout | 300 s | Long forward passes |
From sglang-101 §R1
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
Metal Insufficient Memory | Pool took 87 percent of free memory | --mem-fraction-static 0.4 |
RuntimeError on first batch, MLX | --disable-overlap-schedule | Keep overlap on |
| Retractions again and again | Admission forecast too bold | Raise --schedule-conservativeness |
| High TTFT, fast TPOT | Past the knee, requests queue | Cap concurrency at the knee |
No cached_tokens in usage | No --enable-cache-report | Add the flag |
#cached-token near 0 | Changing id at prompt start | Put shared text first |
| "health check failed" under load | No detokenizer output for 20 s | Use /ready for readiness |
| Crash line at shutdown | SIGTERM to the process group | SIGTERM to the main process |
From sglang-101 §R3, sglang-101 §2.3, sglang-101 §1.2, sglang-101 §3.4, sglang-101 §5.1
Glossary#
- TTFT
- time to first token. Send to first streamed chunk.
- TPOT
- time per output token, after the first token.
- ITL
- inter-token latency. Gap between two streamed chunks.
- KV cache
- stored keys and values of earlier tokens.
- TP
- tensor parallelism. Layer weights cut into slices per GPU.
- DP
- data parallelism. Full model copies with own KV cache.
- EP
- expert parallelism. MoE experts divided among GPUs.
- PD
- prefill-decode disaggregation. Separate prefill and decode servers.
From sglang-101 §R4, sglang-101 §3.3, sglang-101 capture: bench-shared-prefix.txt
Q&A#
- Why three processes?
- The GIL. Text work must not delay GPU steps.
- How many 256 in, 512 out requests fit 4,096 tokens?
- Five. Each reserves 768.
- Why 2,998 cached of 2,999?
- The last prompt token always prefills.
- Gauge 0.942, counters 0.636?
- Gauge is the last interval. Trust the counters.
- What is the knee?
- The cap where throughput stops rising. Here at or below 8.
From sglang-101 §2.1, sglang-101 §2.3, sglang-101 §3.3, sglang-101 §5.2, sglang-101 §5.1
Tips#
- Pass
--random-range-ratio 1.0in every benchmark. - Report throughput with p50 and p99 TTFT and TPOT.
- Raise
--mem-fraction-staticin steps of 0.02 only. - Keep the radix cache on. Measure hit rate per feature.
- Pin
lmsysorg/sglang:v0.5.22, neverlatest. - Mount
~/.cache/sglangon a persistent volume.
From sglang-101 §5.1, sglang-101 §3.2, sglang-101 §3.3, sglang-101 §7.1