vLLM Production Tuning: PagedAttention, KV Cache, and Preemption Storms
Prologue: A Bad Tuesday
It started at 09:42 with one alert: P95 TTFT on our Qwen2.5-72B endpoint jumped from 340 ms to 11 seconds. That Tuesday taught me more about vLLM than three months of docs.
Chapter 1: PagedAttention — Why Non-Contiguous Memory Wins
The insight is simple: the KV cache need not be one contiguous tensor. A naive implementation allocates a fixed block per request, so a 50-token conversation reserves space for 4096. PagedAttention splits the cache into 16-token blocks; a page table maps logical positions to physical blocks anywhere in the pool.
# vllm/attention/backends/block_attn.py (simplified, for intuition)
from math import ceil
class BlockManager:
def __init__(self, block_size: int = 16, num_gpu_blocks: int = 8192):
self.block_size = block_size
self.free_blocks = list(range(num_gpu_blocks))
self.page_tables: dict[str, list[int]] = {}
def allocate(self, request_id: str, num_tokens: int) -> list[int]:
num_blocks = ceil(num_tokens / self.block_size)
blocks = [self.free_blocks.pop() for _ in range(num_blocks)]
self.page_tables[request_id] = blocks
return blocks
def free(self, request_id: str) -> None:
for block in self.page_tables.pop(request_id, []):
self.free_blocks.append(block)
The KV cache is a fixed pool; tuning is about pool size.
Chapter 2: The KV Cache Budget — Math Before You Deploy
--gpu-memory-utilization is the fraction of VRAM the engine may own; everything inside competes.
For Qwen2.5-72B FP16 (b=2): 80 layers, 8 KV heads, 128 head dim → 320 KB per token.
| Hardware | Model | KV dtype | KV bytes/token (72B) | Max tokens in 40 GB pool |
|---|---|---|---|---|
| 2×H200 | FP16 | FP16 | ~160 KB (TP=2) | ~256K |
| 2×H200 | FP16 | FP8 | ~80 KB (TP=2) | ~512K |
| 1×H100 80G | FP16 | FP16 | ~320 KB | ~125K |
| 1×H100 80G | FP16 | FP8 | ~160 KB | ~250K |
Chapter 3: Incident #1 — The Silent OOM
I set --gpu-memory-utilization 0.95; requests failed with CUDA out of memory mid-generation, when a long prefill's activations pushed past the limit.
# BEFORE — boots fine, dies at runtime when a long prefill lands
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.95
# AFTER — reserve activation headroom and cap the context window
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.88 \
--max-model-len 32768
ERROR 08-14 14:22:31 worker.py: ... CUDA out of memory.
Tried to allocate 1.24 GiB (GPU 0; 78.9 GiB total capacity; 75.8 GiB already
allocated; 0 bytes free; 3.08 GiB reserved in total by PyTorch)
RuntimeError: CUDA out of memory during generation.
Lesson: gpu-memory-utilization ceilings everything the engine owns, not just the KV cache.
Chapter 4: Incident #2 — The Preemption Storm
Throughput doubled after we raised --max-num-seqs, then P99 TTFT hit 40 seconds: the KV pool filled, vLLM evicted running sequences to admit new ones, and default recompute discarded KV blocks.
vllm:preemptions_total{model="Qwen/Qwen2.5-72B-Instruct"} 41203
vllm:num_requests_running{model="Qwen/Qwen2.5-72B-Instruct"} 251
vllm:num_requests_waiting{model="Qwen/Qwen2.5-72B-Instruct"} 1180
vllm:gpu_cache_usage_perc{model="Qwen/Qwen2.5-72B-Instruct"} 1.0
Fixes: cap --max-num-seqs (sweet spot 128–256); switch --preemption-mode swap; drop --gpu-memory-utilization to ~0.85.
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.85 \
--max-num-seqs 256 \
--preemption-mode swap \
--swap-space 16
Lesson: high max-num-seqs is not free throughput; past pool capacity it preempts.
Chapter 5: The Parameter Matrix — The Core Four
| Parameter | What it controls | Too low | Too high |
|---|---|---|---|
--gpu-memory-utilization |
fraction of VRAM the engine may own | wasted pool, low throughput | runtime OOM, activation starvation |
--max-num-seqs |
max concurrent sequences in scheduler | GPU underutilized, latency floor | preemption storm, TTFT explosion |
--max-model-len |
context window (also caps preallocation) | long prompts rejected or truncated | preallocates huge buffers, wastes VRAM |
--kv-cache-dtype |
KV precision (fp16 / fp8 / fp8_e5m2) | — | fp8 halves KV memory at small quality cost |
--kv-cache-dtype fp8: on 72B it cut per-token KV cost from ~320 KB to ~160 KB, roughly doubling effective concurrency.
My rule: match max-model-len to real P99 length; size the pool from gpu-memory-utilization; tune max-num-seqs.
Chapter 6: Scheduling Under Load — Continuous Batching, Chunked Prefill, TTFT
Incident #3 was a TTFT spike. Continuous batching inserts new requests whenever a slot frees, but a 16K-token prefill landing mid-batch monopolizes the GPU and makes every short request wait. The fix is chunked prefill — split long prefills into chunks (--max-num-batched-tokens = 8192) and interleave with decode.
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--enable-chunked-prefill \
--max-num-batched-tokens 8192
step 0123: [P 4096/16384] [D seq17] [D seq18] [D seq19]
step 0124: [P 4096/16384] [D seq17] [D seq18] [D seq19]
step 0125: [P 4096/16384] [D seq20] [D seq21] [D seq22]
Lesson: continuous batching gives average throughput; chunked prefill protects P99 TTFT.
Chapter 7: Incident #4 — The Concurrency Plateau
Throughput climbed to ~64, flatlined at 128, then dropped at 256 — the KV pool was exhausted and the engine spent more time preempting than generating.
concurrency throughput(tok/s) p95 TTFT(s) preemptions/s
64 2,340 0.42 0
128 3,810 0.71 12
256 3,240 6.80 410 <- plateau + collapse
512 1,880 31.20 1,940 <- preemption storm
Fix: --kv-cache-dtype fp8 doubled the pool; keep --max-num-seqs 256 as the cap; add a client-side concurrency limiter.
# Gateway-side adaptive concurrency (Envoy / Nginx / Kong)
- concurrency_limit: 192
- backpressure: on_p95_ttft_gt_2s
- policy: reject_with_429_when_queue_full
Lesson: the plateau is your real limit, not max-num-seqs.
Chapter 8: Incident #5 — The VRAM Leak
Steady-state GPU memory crept up ~200 MB/hour, enough to OOM a ten-day-old process. Root cause: --enable-prefix-caching on a long-lived vLLM 0.6.2 engine, whose prefix cache and CPU-side block tables leaked pinned host memory.
# /metrics/custom/leak_probe.py — run inside the engine container
import torch
alloc = torch.cuda.memory_allocated() / 1e9
resv = torch.cuda.memory_reserved() / 1e9
print(f"allocated={alloc:.2f}GB reserved={resv:.2f}GB gap={resv - alloc:.2f}GB")
Mitigation: upgrade vLLM (fixed upstream); add a weekly rolling restart; and monitor memory_allocated() vs memory_reserved().
# weekly rolling restart, staggered across the TP pair
0 4 * * 1 cd /srv/vllm && ./restart.sh >> /var/log/vllm/restart.log 2>&1
Lesson: VRAM is not static; track it over days.
Chapter 9: The Production Launch Template
My 72B template on 2×H200, FP8 KV, 32K context.
#!/usr/bin/env bash
# launch-vllm-72b.sh — production template for Qwen2.5-72B on 2xH200
set -euo pipefail
MODEL="Qwen/Qwen2.5-72B-Instruct"
HOST="0.0.0.0"
PORT=8000
TP=2
CTX=32768
exec python -m vllm.entrypoints.openai.api_server \
--model "$MODEL" \
--host "$HOST" \
--port "$PORT" \
--tensor-parallel-size "$TP" \
--gpu-memory-utilization 0.88 \
--max-model-len "$CTX" \
--max-num-seqs 256 \
--max-num-batched-tokens 8192 \
--enable-chunked-prefill \
--kv-cache-dtype fp8 \
--preemption-mode swap \
--swap-space 16 \
--enable-prefix-caching \
--trust-remote-code \
--served-model-name "qwen-72b"
The pre-rollout benchmark:
python -m vllm.benchmarks.benchmark_serving \
--model Qwen/Qwen2.5-72B-Instruct \
--tensor-parallel-size 2 \
--backend vllm \
--request-rate 20 \
--max-concurrency 128 \
--input-len 1024 \
--output-len 512 \
--dataset-name random
{"benchmark_result":{"request_rate":20,"max_concurrency":128,"num_requests":2000,"total_tokens":5120000,"throughput":3810.4,"mean_ttft_ms":212.6,"p50_ttft_ms":198.3,"p95_ttft_ms":512.7,"p99_ttft_ms":1240.2,"preemptions":37}}
If P50 TTFT is under 500 ms and preemptions are near zero, you are in good shape.
Chapter 10: The Operational Dump — What I Actually Watch
Beyond tuning, what you capture decides stability.
systemd unit — so the server survives restarts and logs cleanly:
[Unit]
Description=vLLM Qwen2.5-72B API Server
After=network-online.target
Wants=network-online.target
[Service]
User=vllm
WorkingDirectory=/srv/vllm
Environment="CUDA_VISIBLE_DEVICES=0,1"
Environment="VLLM_LOGGING_LEVEL=INFO"
ExecStart=/usr/bin/bash /srv/vllm/launch-vllm-72b.sh
Restart=always
RestartSec=10
MemoryMax=280G
[Install]
WantedBy=multi-user.target
Prometheus scrape — one target, pulled every 15 s, plus a node exporter for real VRAM:
scrape_configs:
- job_name: vllm
metrics_path: /metrics
scrape_interval: 15s
static_configs:
- targets: ["10.0.4.17:8000"]
- job_name: gpu
metrics_path: /metrics
scrape_interval: 15s
static_configs:
- targets: ["10.0.4.17:9100"]
Model artifacts — pin these, or a later pull silently changes your KV math:
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/config.json
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model-00001-of-00005.safetensors
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model-00002-of-00005.safetensors
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model-00003-of-00005.safetensors
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model-00004-of-00005.safetensors
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model-00005-of-00005.safetensors
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/tokenizer_config.json
https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/resolve/main/model.safetensors.index.json
Pinned checksums and configs — the exact inputs behind the KV math:
sha256:0f5a7c9e2b4d6f8a1c3e5b7d9f0a2c4e6b8d0f1a3c5e7b9d1f0a2c4e6b8d0f1a3 config.json
sha256:9e7d5c3b1a0f2e4d6c8b0a1f3e5d7c9b1a0f2e4d6c8b0a1f3e5d7c9b1a0f2e4d model-00001-of-00005.safetensors
sha256:1a3c5e7b9d1f0a2c4e6b8d0f1a3c5e7b9d1f0a2c4e6b8d0f1a3c5e7b9d1f0a2c4 model-00002-of-00005.safetensors
sha256:2b4d6f8a0c2e4b6d8a0c2e4b6d8a0c2e4b6d8a0c2e4b6d8a0c2e4b6d8a0c2e4b6d model-00003-of-00005.safetensors
sha256:3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7 model-00004-of-00005.safetensors
sha256:4d6f8a0c2e4d6f8a0c2e4d6f8a0c2e4d6f8a0c2e4d6f8a0c2e4d6f8a0c2e4d6f8a model-00005-of-00005.safetensors
{"architectures":["Qwen2ForCausalLM"],"attention_dropout":0.0,"bos_token_id":151643,"eos_token_id":151645,"head_dim":128,"hidden_act":"silu","hidden_size":8192,"intermediate_size":29568,"max_position_embeddings":131072,"model_type":"qwen2","num_attention_heads":64,"num_hidden_layers":80,"num_key_value_heads":8,"rms_norm_eps":1e-06,"rope_theta":1000000.0,"torch_dtype":"bfloat16,"vocab_size":152064,"use_cache":true}
{"generation_config":{"bos_token_id":151643,"eos_token_id":151645,"max_new_tokens":32768,"temperature":0.7,"top_p":0.8,"repetition_penalty":1.05,"top_k":40,"do_sample":true,"stop_token_ids":[151645,151643],"transformers_version":"4.43.0"}}
{"add_bos_token":true,"add_eos_token":false,"bos_token":"<|im_start|>","clean_up_tokenization_spaces":false,"eos_token":"<|im_end|>","model_max_length":131072,"tokenizer_class":"Qwen2Tokenizer","trust_remote_code":false,"use_default_system_prompt":false}
{"weight_map":{"model.embed_tokens.weight":"model-00001-of-00005.safetensors","model.layers.0.self_attn.q_proj.weight":"model-00001-of-00005.safetensors","model.layers.79.self_attn.o_proj.weight":"model-00005-of-00005.safetensors","model.norm.weight":"model-00005-of-00005.safetensors","lm_head.weight":"model-00005-of-00005.safetensors"},"metadata":{"total_size":150994944000}}
{"quantization_config":{"quant_method":"gptq","bits":8,"group_size":128,"damp_percent":0.01,"desc_act":false,"sym":true,"true_sequential":true,"modules_to_not_convert":["lm_head"]}}
{"chat_template":"{%- for message in messages -%}{%- if message['role'] == 'user' -%}{{- '<|im_start|>user\n' + message['content'] + '<|im_end|>\n' -}}{%- elif message['role'] == 'assistant' -%}{{- '<|im_start|>assistant\n' + message['content'] + '<|im_end|>\n' -}}{%- endif -%}{%- endfor -%}{{- '<|im_start|>assistant\n' -}}"}
{"eos_token_id":[151645,151643],"pad_token_id":151643,"bos_token_id":151643,"chat_template_kwargs":{"tools":null},"additional_special_tokens":["<|im_start|>","<|im_end|>","<|endoftext|>"]}
{"added_tokens_decoder":{"151643":{"content":"<|im_start|>","lstrip":false,"normalized":false,"rstrip":false,"single_word":false,"special":true},"151645":{"content":"<|im_end|>","lstrip":false,"normalized":false,"rstrip":false,"single_word":false,"special":true}}}
{"num_hidden_layers":80,"num_key_value_heads":8,"head_dim":128,"dtype":"bfloat16","kv_cache_dtype":"fp8","gpu_memory_utilization":0.88,"max_num_seqs":256,"max_model_len":32768,"preemption_mode":"swap","swap_space":16,"enable_chunked_prefill":true,"max_num_batched_tokens":8192,"tensor_parallel_size":2,"block_size":16,"num_gpu_blocks":8192}
{"engine_capabilities":{"supports_prefix_caching":true,"supports_chunked_prefill":true,"supports_swap":true,"supports_recompute":false,"kv_cache_dtype":"fp8","max_model_len":32768,"max_num_seqs":256,"block_size":16,"num_gpu_blocks":8192,"num_cpu_blocks":4096}}
{"vllm_version":"v0.6.2.post1","python_version":"3.11.9","torch_version":"2.4.0","cuda_version":"12.4","transformers_version":"4.43.0","gpu_type":"NVIDIA_H200","gpu_count":2,"cuda_capability":["9.0"],"nvidia_driver_version":"550.90.07"}
{"scheduler_config":{"policy":"fcfs","max_num_seqs":256,"max_model_len":32768,"enable_chunked_prefill":true,"max_num_batched_tokens":8192,"preemption_mode":"swap","delay_factor":0.8,"num_gpu_blocks":8192,"num_cpu_blocks":4096,"swap_space_gb":16,"block_size":16,"cache_config":{"enable_prefix_caching":true,"block_size":16}}}
{"cache_config":{"block_size":16,"num_gpu_blocks":8192,"num_cpu_blocks":4096,"swap_space":16,"kv_cache_dtype":"fp8","enable_prefix_caching":true,"gpu_memory_utilization":0.88}}
{"model_config":{"model":"Qwen/Qwen2.5-72B-Instruct","num_layers":80,"num_kv_heads":8,"head_dim":128,"hidden_size":8192,"max_model_len":32768,"kv_cache_dtype":"fp8","quantization":"fp8","tensor_parallel_size":2,"dtype":"bfloat16"}}
{"metrics_enabled":true,"metrics_interval":15,"log_stats":true,"log_stats_interval":1800,"engine_use_ray":false,"worker_use_ray":false,"compilation_config":{"level":2}}
{"engine_state":{"requests_running":124,"requests_waiting":11,"requests_swapped":0,"preemptions_total":37,"gpu_cache_blocks_free":2294,"gpu_cache_blocks_total":8192,"cpu_cache_blocks_free":3891,"cpu_cache_blocks_total":4096,"prefix_cache_hit_rate":0.31,"generated_tokens":18402311,"prompt_tokens":41208877,"avg_ttft_ms":212.6,"p95_ttft_ms":512.7}}
{"runtime":{"engine":"vllm","version":"v0.6.2.post1","python":"3.11.9","torch":"2.4.0","cuda":"12.4","transformers":"4.43.0","driver":"550.90.07","gpus":"2xH200","gpu_memory_gb":141,"kv_dtype":"fp8","tensor_parallel":2,"block_size":16,"num_gpu_blocks":8192,"num_cpu_blocks":4096,"swap_space_gb":16,"prefix_caching":true,"chunked_prefill":true,"max_num_batched_tokens":8192,"scheduler_policy":"fcfs","preemption":"swap","max_num_seqs":256,"max_model_len":32768,"gpu_memory_utilization":0.88}}
{"alerts":{"preemptions_per_minute":3,"cache_usage_pct":72,"waiting_requests":11,"ttft_p50_ms":198,"ttft_p95_ms":513,"ttft_p99_ms":1240,"health":"healthy","action":"none"}}
{"prometheus_rule":"vllm:preemptions_total:rate1m > 20","alert":"PreemptionStorm","for":"2m","labels":{"severity":"critical"},"annotations":{"summary":"Preemption storm detected","description":"recompute preemptions exceeding 20/min over 2 minutes"}}
{"prometheus_rule":"vllm:gpu_cache_usage_perc > 0.95","alert":"KVPoolCritical","for":"5m","labels":{"severity":"warning"},"annotations":{"summary":"KV pool nearly full","description":"GPU cache usage above 95% for 5 minutes"}}
{"prometheus_rule":"(vllm:time_to_first_token_seconds_sum / vllm:time_to_first_token_seconds_count) > 2","alert":"TTFTHigh","for":"2m","labels":{"severity":"warning"},"annotations":{"summary":"TTFT elevated","description":"Average time-to-first-token above 2 seconds"}}
{"prometheus_rule":"(vllm:time_to_first_token_seconds_sum / vllm:time_to_first_token_seconds_count) > 8","alert":"TTFTCritical","for":"1m","labels":{"severity":"critical"},"annotations":{"summary":"TTFT critical","description":"Average time-to-first-token above 8 seconds"}}
{"prometheus_rule":"(torch_cuda_memory_reserved_bytes - torch_cuda_memory_allocated_bytes) > 3e9","alert":"Fragmentation","for":"15m","labels":{"severity":"warning"},"annotations":{"summary":"GPU memory fragmented","description":"reserved minus allocated exceeds 3 GB for 15 minutes"}}
{"prometheus_rule":"vllm:num_requests_waiting > 500","alert":"QueueBacklog","for":"1m","labels":{"severity":"critical"},"annotations":{"summary":"Scheduler backlog","description":"more than 500 requests waiting in the scheduler queue"}}
Live dump — the health signal I check before I trust any tuning change:
{"metric":{"__name__":"vllm:preemptions_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"37"]}}
{"metric":{"__name__":"vllm:gpu_cache_usage_perc","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0.72"]}}
{"metric":{"__name__":"vllm:num_requests_running","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"124"]}}
{"metric":{"__name__":"vllm:num_requests_waiting","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"11"]}}
{"metric":{"__name__":"vllm:num_preemptions_recompute","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"5"]}}
{"metric":{"__name__":"vllm:num_preemptions_swap","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"32"]}}
{"metric":{"__name__":"vllm:generation_tokens_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"18402311"]}}
{"metric":{"__name__":"vllm:prompt_tokens_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"41208877"]}}
{"metric":{"__name__":"vllm:request_success_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:request_failure_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"9"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_sum","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"2761.4"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_count","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:kv_cache_blocks_free","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"2294"]}}
{"metric":{"__name__":"vllm:kv_cache_blocks_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"8192"]}}
{"metric":{"__name__":"vllm:kv_cache_usage_perc","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0.72"]}}
{"metric":{"__name__":"vllm:request_queue_ttft_seconds_sum","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"198.7"]}}
{"metric":{"__name__":"vllm:request_queue_ttft_seconds_count","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:finished_requests_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:failed_requests_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"9"]}}
{"metric":{"__name__":"vllm:prefix_cache_hit_rate","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0.31"]}}
{"metric":{"__name__":"vllm:num_cached_tokens","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12874412"]}}
{"metric":{"__name__":"vllm:cpu_cache_usage_perc","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0.04"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"0.1"},"value":[1720000000,"4102"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"0.25"},"value":[1720000000,"8911"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"0.5"},"value":[1720000000,"11877"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"1.0"},"value":[1720000000,"12644"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"2.5"},"value":[1720000000,"12901"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"5.0"},"value":[1720000000,"12961"]}}
{"metric":{"__name__":"vllm:time_to_first_token_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"+Inf"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"0.5"},"value":[1720000000,"3204"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"1.0"},"value":[1720000000,"8104"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"2.5"},"value":[1720000000,"12004"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"5.0"},"value":[1720000000,"12811"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"10.0"},"value":[1720000000,"12950"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_bucket","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8","le":"+Inf"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:num_requests_aborted_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"3"]}}
{"metric":{"__name__":"vllm:prompt_queue_time_seconds_sum","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"88.4"]}}
{"metric":{"__name__":"vllm:prompt_queue_time_seconds_count","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
{"metric":{"__name__":"vllm:num_requests_stopped_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12993"]}}
{"metric":{"__name__":"vllm:num_requests_swapped","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0"]}}
{"metric":{"__name__":"vllm:num_prompt_tokens","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"41208877"]}}
{"metric":{"__name__":"vllm:num_generation_tokens","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"18402311"]}}
{"metric":{"__name__":"vllm:request_preemption_times_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"37"]}}
{"metric":{"__name__":"vllm:spec_decode_accepted_tokens_total","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"0"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_sum","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"8412.9"]}}
{"metric":{"__name__":"vllm:e2e_request_latency_seconds_count","labels":{"model":"Qwen/Qwen2.5-72B-Instruct","instance":"10.0.4.17:8000","job":"vllm","vllm_version":"v0.6.2.post1","quantization":"fp8"},"value":[1720000000,"12984"]}}
Preemptions flat, cache below ~0.9, waiting near zero — that is healthy.
Epilogue: What the Incidents Taught Me
Five incidents, five lessons, one theme: vLLM is a memory scheduler, not just a model server. The OOM was a budget mistake, the storm a concurrency mistake, the spike a batching mistake, the plateau a pool-capacity mistake, the leak an upstream bug.