TT Lab
Blog

한국어 English 日本語 中文

Get started
Blog

Blog

NVIDIA Dynamo: Splitting Prefill and Decode, and Sending to Where the KV Exists

Status: Draft (2026-10-13), partially measured. Papers, official documentation, and the NVIDIA blog were directly opened and verified on 2026-10-13, and the documentation is based on Dynamo v1.5.1 (2026-10-07). Performance figures released by NVIDIA are marked as "Vendor Announcement." Measurements were re-cited from "Toss ML/AI Infra Prep" Part 14 (8GB-class GPU, vLLM) and Part 24 (Dynamo 1.6.0 dev build, 8GB-class and 24GB-class GPUs, 0.6B model) on the same site. The disaggregated serving benefits in NVLink- and RDMA-connected environments are unmeasured. Writing rules: Measured data is the default; unmeasured items are marked as "Unmeasured," and items that could not be verified are marked as "Unverified."

NVIDIA Dynamo: Splitting Prefill and Decode

Table of Contents

1. Prefill and Decode Interfere with Each Other on the Same GPU

긴 프롬프트가 끼어들 때 디코드에 생기는 일 요청 A 가 15ms 마다 토큰을 내는 중, 긴 프롬프트 B 가 들어온다 (가) 한 GPU 에서 함께 GPU B 프리필 A 의 다음 토큰이 227ms 늦다(실측) (나) 프리필·디코드 분리 디코드 GPU B 의 토큰 → 프리필 GPU B 프리필 KV 전송 0ms 200ms 400ms 600ms · 분리하면 A 의 토큰 간격은 고르게 유지된다. · 대신 B 의 첫 토큰에 KV 를 옮기는 시간이 더해진다. 전송 시간 = 토큰당 KV × 입력 토큰 ÷ 링크 속도 227ms: 8GB급 GPU·vLLM 기본 청크 2,048 실측. 전송 길이는 설명용.
Figure: How a long prompt interrupts decode and how it looks when separated

As mentioned in Part 1, prefill is bound by compute, while decode is bound by memory bandwidth. Problems arise when the two share a single GPU. Continuous batching inserts the prefill of a new request between decode steps, but steps with long prefills take a long time, during which other requests in the batch cannot receive their next token.

Our Measurement. On an 8GB-class GPU with default vLLM settings (max input per step 2,048 tokens), inserting a 3,500-token input alongside a request currently undergoing decoding resulted in a maximum token interval of 227ms in that segment (227, 226, and 226ms across 3 trials). The usual interval is about 15ms. Chunked prefill from Part 2 could reduce this value down to 69ms, but at the cost of slightly delaying the first token of long inputs. Chunking only distributes the interference, it does not eliminate it.

Two papers that systematically addressed disaggregated serving for the first time point out this problem as follows.

2. Disaggregated Serving: Split and Move the KV

The method is simple. Maintain separate GPUs dedicated to prefill and GPUs dedicated to decode. Once the prefill GPU generates the prompt's KV, it sends that KV to the decode GPU, and the decode GPU continues token generation using the received KV.

Results from DistServe. Measured on A100 80GB (NVLink within nodes, 25Gbps between nodes) using OPT-13B, 66B, and 175B for the maximum request rate (goodput) satisfying latency targets by 90% or more.

Workload Model Request Rate vs. vLLM Latency Target Strictness vs. vLLM
Chatbot (ShareGPT) OPT-13B, 66B, 175B 2.0x–4.6x 1.8x–3.2x stricter
Code Completion (HumanEval) OPT-66B 5.7x 1.4x stricter
Summarization (LongBench) OPT-66B 4.3x 12.6x stricter

Compared to another baseline (DeepSpeed-MII), it was up to 7.4x, and the abstract's statement "up to 7.4x request rate or 12.6x stricter latency target" combines these two tables. Synchronization examples are also intuitive. Putting a 13B model on a single A100 achieved about 1.6 requests/sec, whereas prefill alone achieved 5.6, decode alone achieved 10 requests/sec, and splitting into 2 prefill + 1 decode GPUs yielded 3.3 requests/sec per GPU, a 2.1x increase.

What about KV transfer? The paper calculates that a single 512-token request for OPT-66B amounts to about 1.13GB of KV, requiring 11.3GB/s at 10 requests/sec. Therefore, it was designed to place prefill and decode within the same node (NVLink) , resulting in KV transfer accounting for less than 0.1% of total latency in OPT-175B.

Results from Splitwise. KVs were sent asynchronously layer by layer to overlap with the next layer's computation (InfiniBand). Unoverlapped transfers took about 8ms on A100 and about 5ms on H100, which was less than 7% of prompt computation time and added 0.8% to total latency. Under equal power conditions, an A100-only split configuration achieved 2.15x the throughput of the baseline (A100) (Figure 18a in the paper). The representative figures in the abstract ("1.4x at 20% cost reduction," "2.35x at equal cost/power") could not be matched with pairs from the main experiments, so only main text values are noted here.

3. Architecture of NVIDIA Dynamo

Dynamo: 분리 서빙과 KV 인지 라우팅 프런트엔드 OpenAI 호환 API · 토큰화 KV 인지 라우터 워커마다 비용 = 새로 계산할 프리필 블록 (이미 가진 블록은 뺌) + 디코드 부하 → 가장 싼 곳 블록 색인 워커 1: ■■■□ 워커 2: ■□□□ 프리필 워커 계산 위주 · 큰 텐서 병렬 등 워커 1 워커 2 디코드 워커 메모리 위주 · 큰 배치 워커 3 워커 4 NIXL 로 KV 전송 NVLink · RDMA(UCX) · TCP · 저장소(GDS 등) ↑ 워커가 블록 저장·삭제 이벤트를 라우터에 알림 플래너 대기열·KV 사용률·지연 목표를 보고 프리필·디코드 워커 수를 늘리고 줄인다 KV 오프로딩 GPU → CPU → 디스크 → 객체 KVBM(1.5 에서 폐지 예고) 또는 LMCache 등 엔진 연결
Figure: Dynamo architecture: Frontend, KV-aware router, prefill/decode workers, NIXL, planner

Dynamo is a serving framework that ties together multiple GPUs and multiple nodes on top of engines like vLLM, SGLang, and TensorRT-LLM. It does not replace engines; instead, it handles how to partition multiple engines and where to send requests. The architecture confirmed in the documentation (v1.5.1) is as follows.

4. Why Throughput Increases

Source What Changes Basis
Interference Elimination Long prefills do not disrupt the decode GPU, allowing larger decode batches while meeting token interval targets Measurement (227ms interference), DistServe, Splitwise
Phase-Specific Tuning Different parallelism, GPU counts, and hardware are assigned to prefill and decode. The planner adapts ratios to load DistServe (2.1x example), Splitwise
Cache Hit Requests are sent to workers sharing the same prefix, bypassing prefill entirely Measurement (Section 5), Vendor Announcement
Workset Partitioning Prefixes diverge across workers, fitting each worker's share entirely into its GPU cache Measurement (Section 5)

NVIDIA's announced performance figures are as follows. All are Vendor Announcementsand have not been independently reproduced.

5. Dynamo Measured Directly

We measured Dynamo (1.6.0 dev build, vLLM 0.30.0, NIXL 1.3.2) in a separate series using Qwen3-0.6B (114,688 bytes of KV per token).

KV-Aware Routing. We spun up two workers and sent 12 types of prefixes of about 1,500 words each, mixed in 6-fold repetition (60 repeat requests). When a repeat request went to a worker that already had the matching prefix KV, the time to first token was about 15ms; otherwise, it was about 80ms.

Routing Hits out of 60 (3 iterations) Average Time to First Token
Round Robin 35, 40, 43 34~42ms
Random 44, 31, 45 32~46ms
KV-aware, Approximation Mode 60, 53, 60 15~26ms
KV-aware, Event Mode (No Events) 39, 44, 41 32~38ms
KV-aware, Event Mode 60, 60, 60 15ms

Disaggregated Serving. The results were the opposite. Everything was slower than single serving.

Configuration (Concurrency 1) 1,500 Words 3,000 Words
Single 8GB-class GPU 78ms 172ms
Splitting one GPU into prefill and decode processes 406ms 812ms
Splitting across two different servers (1GbE-class link) 1,721~1,752ms 3,407~3,533ms

This does not mean "disaggregated serving is slow," but rather **"splitting over a slow link is slow."** This table explains why papers presuppose NVLink or InfiniBand.

6. Relationship Between Dynamo and LMCache

The two are not competitors; they operate at different layers. LMCache is a cache layer that stores and loads KV alongside a single engine, while Dynamo is a framework that orchestrates, splits, and dispatches across multiple engines. The integration points identified in the documentation are as follows.

7. When There Is No Benefit

The cost-benefit trade-off of disaggregated serving can be estimated using an equation similar to the one in Part 3: Time added to first token ≈ KV per token × input tokens ÷ link throughput(layered transfers allow some portion to be hidden overlapping with computation). Calculating the time to transfer KV for a 4,096-token input yields the following (transfer time only, excluding computation).

Link speeds are roughly 1GbE-class for our measured effective 104MB/s, 100Gb/s for a theoretical 12.5GB/s, and NVLink-class for the 600GB/s between A100s reported in the DistServe paper.

Model KV Size 1GbE-class 100Gb/s NVLink-class
Qwen3-0.6B 470MB 4.5s 38ms 0.8ms
Llama 3.1 8B 537MB 5.2s 43ms 0.9ms
Llama 3.1 70B 1.34GB 12.9s 107ms 2.2ms

If this cost exceeds what can be saved (decoding slowed down by interference, or over-provisioned GPUs), it results in a net loss. Consequently, disaggregation yields no benefit or is detrimental in the following scenarios:

Dynamo documentation also notes that there is no universal threshold. Because boundaries shift depending on the model, GPU, and input length distribution, the initial release (v0.1.0) utilized remote prefill "only when the prefill length minus prefix hits exceeded the threshold and the remote prefill queue was short." In v1.5.1, conditional splitting based on router overhead has entered the experimental stage. It is safest to decide whether to disaggregate after first measuring your link's KV transfer throughput and evaluating the equation above with that value.

KV-aware routing is a different story. Because it moves requests toward the KV rather than moving the KV , there is no link overhead. Under workloads where identical prefixes recur frequently, it is relatively unlikely to incur losses. However, you must tune load weights to prevent overloading a single worker and verify that events are actually arriving.

8. Series Summary

Part What Is Saved When Most Effective When Absent
1. KV Cache Recomputation of past tokens' K and V Always (outputs are identical) — Consumes memory instead
2. PagedAttention, Continuous Batching, Prefix Cache Memory waste, fragmentation, redundant prefix computation High concurrent requests, shared prompts Cache eviction when working set exceeds GPU capacity
3. LMCache Replacing prefill with KV stored outside the GPU Long context, high reuse, fast storage paths Short inputs, low hit rates, slow links, small capacity
4. Dynamo Interference removal, phase-specific tailoring, routing to KV High load, long prompts, fast inter-GPU links Slow links, single card, low load, small models

A single question runs through all four parts: "Which is cheaper: recomputing this KV, or fetching it from somewhere else?" The answer is determined by the model's KV size per token, the GPU's compute speed, the speed of the path the KV travels, and how frequently the same prefix recurs. All four are measurable values.

A TT Note. If you put someone practicing serves and someone practicing rallies on the same table, they both lose out waiting for each other to clear the ball. Splitting the tables makes it better. But what if you have to carry baskets of balls over from the next building? In that case, you are better off just playing together. Measure how fast the ball basket arrives before you split.

References

Sign in to like

Comments

No comments yet.

Sign in to leave a comment