系列:Inference Systems Infrastructure Notes

Inference Systems Infrastructure Notes (9): The KV Cache Landscape — Why It Decides Your Throughput, Latency and Concurrency

0. The One-Line Thread

KV Cache is space traded for time: it pays once to compute the repeated work in autoregressive generation and caches the result, at the cost of GPU memory growing linearly with batch times sequence length, which eventually throttles your concurrency. This post covers three things — why it can be cached at all, how big it actually gets, and which directions the industry is cutting it from.

1. Meet the Enemy: Without KV Cache, What Are We Recomputing?

LLM inference is autoregressive: generating token n requires information from all previous n−1 tokens. Naively, every new token re-runs the whole history through the forward pass:

ModuleWhere the redundancy lives
EmbeddingHistorical token embeddings regenerated every step
K / V generationK and V for historical tokens recomputed every step
QKᵀThe attention score matrix recomputed, growing quadratically with sequence length
Softmax × VThe weighted sum recomputed

Total cost for N tokens lands around O(N²) — the longer the sequence, the worse it gets, and it gets ugly fast.

Figure 1: KV Cache during prefill and decode prefill: the whole prompt in one pass, emits the first token tok1 tok2 tok3 KV Cache, 3 slots out decode: one token per step, but attention reads the entire history tok4 KV Cache, 4 slots (+1) out Green marks what this step adds. Decode work per step is constant (one token), but the KV it reads grows linearly — the source of memory-bound behaviour.
Figure 1: prefill builds the KV Cache for the whole prompt in one shot; decode adds one token per step, and attention reads the entire history.

Caching rests on two properties: causal masking and position independence.

Attention: causal masking freezes the past

FFN / LayerNorm / Linear: positions do not interact

The one-line mathematical backing

Matrix multiplication is block-separable: split A into [:s] and [s:], multiply each by B, concatenate — identical to multiplying A by B whole. Attention and FFN are both matrix multiplications, so caching [:s] and computing only the new [s:] is exactly equivalent. This is a lossless optimization.

3. Prefill vs Decode: Two Stages, Opposite Personalities

StageWhat it doesCompute profileKey metric
prefillProcesses the whole prompt, builds the KV Cache, emits the first tokenCompute-bound (large GEMMs, high parallelism)TTFT
decodeEmits one token at a time, reading the full history each stepMemory-bandwidth-bound (little compute, lots of KV traffic)TPOT

This split — one wants FLOPs, the other wants bandwidth — is the entire reason PD disaggregation exists (see sys8).

4. How Big Does It Actually Get

The formula for standard MHA/GQA:

KV Cache = 2 (K and V) x layers x batch x seq_len x kv_dim x dtype_bytes

where kv_dim = num_kv_heads x head_size.

Measured case (Qwen3-32B):

Takeaway: KV Cache grows linearly with batch and sequence length. Under high concurrency and long contexts, it — not the weights — is what caps your serving concurrency.

5. How It Eats Performance: Three Metrics, Three Memory Regions

MetricMeaningDriven by
TTFTTime to first tokenMostly prefill cost; prefix cache hits cut it sharply
TPOTTime per output tokenPer-step decode cost; rises as KV grows (more traffic)
ThroughputOutput tokens per second (the cost metric)Larger batches help, until memory runs out

Memory view:

peak memory = model weights (fixed) + KV Cache (grows with batch x seq) + activations
total latency = TTFT + TPOT x number of generated tokens

So shrinking KV Cache pays twice: more concurrency on the same card (memory saved) and faster requests (bandwidth saved).

6. The Optimization Landscape: Three Layers

The survey A Survey on Large Language Model Acceleration based on KV Cache Management organizes the field into three layers.

6.1 Token-level (no model change, no parallelism change)

Selecting, organizing, and compressing at token granularity:

DirectionApproachExamples
SelectionKeep only the most important tokensH2O (heavy hitters), Keyformer, SnapKV, Quest
Budget allocationDistribute cache budget across layers / headsPyramidKV, PyramidInfer, AdaKV, DuoAttention
MergingMerge similar or overlapping KV pairsIntra / inter-layer merging, Prompt Cache
QuantizationLower storage precision (FP16 to INT8 / INT4 / FP8)KV cache quantization, see op2
Low-rank decompositionCompress KV matrices into lower-dimensional formLoRA-style compression, one of the ideas behind MLA

6.2 Model-level (architectural changes)

6.3 System-level (scheduling and memory management)

7. Five Knobs: Turning “Shrink the KV Cache” Into Quantifiable Actions

Going back to the formula, KV Cache size is a product of five factors, and each factor is an independent entry point:

KnobHow to turn itCost
Sequence lengthSparsity (static window / dynamic eviction), prefix reuseMay drop critical tokens; long-range tasks degrade
Head countMQA / GQA (fewer KV heads)Slight expressiveness loss, now a mainstream default
key_bitsQuantize to INT8 / INT4 / FP8Accuracy loss, needs calibration (see op2)
Head dimensionMLA compresses KV into a low-rank latent; Double Sparsity exploits channel sparsityLarge structural change
LayersCache only some layers (YOCO / CLA / MLKV / LayerSkip)Needs training support or accepts approximation

How to read this: the knobs are not exclusive. Production stacks stack them — for example, “GQA (heads) + FP8 KV (bits) + prefix reuse (length) + PagedAttention (system)” is the most common combination today.

觉得有用?欢迎点赞、收藏,或请作者喝咖啡 ☕️

支付宝收款码

支付宝

微信收款码

微信

💬 留言

评论由 Giscus 驱动(基于 GitHub Discussions)。 当前仓库 NaphJohn/LLM-blog 尚未启用 Discussions:请在 GitHub 仓库 Settings → General → Features 勾选 Discussions 后刷新本页,评论区即自动显示。