Scaling out
Disaggregated prefill and decode
Running prefill and decode on separate GPU pools so each phase gets its own parallelism, batching, and hardware — and when colocated chunked prefill is enough.
Every chat completion has two personalities. Prefill is fat and often compute-bound. Decode is skinny and memory-bound. Colocating them on one GPU — the default in early vLLM-style servers — makes them fight. A 32k-token prefill landing in a decode-heavy batch spikes everyone's TPOT. Chunking helps, but the hardware plan is still coupled.
Disaggregated serving splits the fleet: prefill workers build the KV cache, decode workers generate tokens, and a fast path ships KV between them. DistServe, Splitwise, Mooncake, NVIDIA Dynamo and llm-d all orbit this idea. It is not free. Under tight dual SLOs it can multiply goodput (requests that meet both TTFT and TPOT).
Concepts in this section
Read them in order. Each one builds on the one before.
| Step | Concept | What it answers |
|---|---|---|
| 1 | Prefill–decode interference | Why does a long prompt stall everyone else's stream? |
| 2 | KV transfer | When does shipping the cache fit the TTFT budget? |
| 3 | Sizing the pools | How many prefill GPUs vs decode GPUs? |
| 4 | Failure modes | What new outages appear after the split? |
The request path
- The router sends the prompt to a prefill instance (queue depth, prefix-cache locality, or shard).
- Prefill runs, possibly with TP tuned for TTFT, and materializes KV in paged blocks.
- Metadata and KV blocks transfer to a decode instance (NIXL/UCX, Mooncake store, NVLink P2P, GPU-direct RDMA).
- Decode streams tokens. Prefill frees or retains blocks per caching policy.
Treat chunked prefill as the default. Treat prefill/decode split as the upgrade when metrics say so: TPOT still spiky after chunking, different TP/CP meshes, or different GPU SKUs per phase.
| System | Emphasis |
|---|---|
| DistServe | Goodput under TTFT+TPOT; parallelism per phase; bandwidth-aware placement. OSDI '24. |
| Splitwise | Cost/energy; heterogeneous prefill vs decode hardware. |
| Mooncake | KV as a first-class distributed resource. |
| NVIDIA Dynamo | Production toolkit for disaggregated serving graphs. |
| llm-d | Kubernetes-facing disaggregated vLLM-style serving. |
Engine support is catching up: experimental or production P/D paths in vLLM V1, SGLang and cloud stacks.
In practice: plot TTFT and TPOT vs QPS on one colocated engine; estimate KV bytes for p50/p95; prototype with the engine's connector; split autoscaling signals; add KV-aware routing; load-test a mix of short decode-heavy traffic and rare huge prefills; keep a rollback flag.
Common mistakes
- Splitting before chunked prefill is exhausted. Most dual-SLO pain dies there.
- Ignoring transfer time. 10 GB of cold KV on IB can spend the whole TTFT budget.
- One ratio and one scaler for both pools.
Key takeaways
- Prefill and decode want different batching, parallelism and sometimes different GPUs.
- Disaggregation removes interference at the cost of KV transfer and ops complexity.
- Size pools from GPU-seconds, not 50/50. Stay colocated until dual SLOs or cost force the split.
Further learning
The DistServe OSDI talk is the clearest short framing:
Mooncake: A KVCache-centric Disaggregated Architecture for LLM ServingMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI. It features a KVCache-centric disaggregated architecture that separates the prefill and decoding clusters. It also leverages th…arXiv.org
NVIDIA DynamoA Datacenter Scale Distributed Inference Serving Framework - ai-dynamo/dynamoGitHubRelated
Prefill–decode interference
A long prefill on the same GPU as decode steals SMs and HBM bandwidth, so everyone else's TPOT spikes.
Prefill vs decode
The two phases of LLM inference. Prefill is compute-bound and sets TTFT. Decode is memory-bound and sets TPOT. They interfere when they share a GPU.
Routing, load balancing and scheduling
LLM-aware gateways: KV-cache-aware routing, token-based rate limits, priorities and fairness.