LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 192 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/27
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnInference & Production ScaleDistributed Inference Data Plane
🚀HardInference Optimization

Distributed Inference Data Plane

Follow one 8K-prompt request through routing, prefill, KV transfer, and decode while designing explicit admission, identity, retry, security, and SLO contracts.

28 min read
Learning path
Step 160 of 192 in the full curriculum
GPU Serving & AutoscalingServing Benchmark Engineering

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Request req-8k-017 contains 8,192 prompt tokens. One mixed prefill/decode replica can process it and start generating, but a busy fleet makes its long prefill interrupt several already-streaming replies. Splitting prompt work from token generation removes that interference, then creates a new problem: roughly 2.50 gibibytes (GiB) of key-value (KV) cache state must reach the right decoder before the first token can safely leave the service.

That state is much larger than a routing message, and it isn't interchangeable across model revisions or cache layouts. A fast transfer to the wrong worker is still a failed request. A correct transfer that starts after the decode pool fills is wasted prefill work.

The GPU serving and autoscaling lesson decided how many workers should be ready. Model parallelism mapped one model across ranks and physical links. KV Cache and PagedAttention showed how token state grows and how logical blocks map to rank-local memory. This lesson connects those pieces into a distributed request path with explicit owners at every boundary.

Why isn't a successful network copy enough to declare a KV handoff correct?

Answer

The decoder also needs the same request identity, model and tokenizer revisions, adapter, token positions, KV dtype and layout, layer coverage, and shard mapping. Bytes that arrive intact under the wrong interpretation can produce invalid output or a runtime failure.

One request, two planes

A distributed serving system has two kinds of work.

The control plane makes decisions. It authenticates the caller, applies quotas, discovers healthy workers, chooses a compatible prefill/decode pair, reserves capacity, issues a fenced attempt, and decides whether failed work may retry.

The data plane carries and transforms request data. It tokenizes or receives the canonical prompt tokens, runs prefill, moves the KV cache, runs decode, and streams output tokens. Control messages are usually small. This request uses tensor parallelism (TP) across two ranks, and its KV payload stores 2-byte BFloat16 (BF16) values and occupies gigabytes.

Two aligned lanes for request req-8k-017. The compact control lane routes and reserves compatible prefill worker P7 and decode worker D3, then commits attempt 4. The payload-heavy data lane sends 8,192 prompt tokens to P7, moves a 2.50 GiB BF16 KV cache to D3, and lets only D3 stream output. A commit gate prevents bytes from becoming visible output before identity and completeness checks pass.
Follow the aligned lanes: routing metadata chooses P7 and D3, while the 2.50 GiB KV payload takes the physical path. Decode becomes stream owner only after the commit gate.

The distinction is about ownership, not process names. A router belongs to the control plane while it chooses workers, but its request-forwarding socket participates in the data path. A worker reports health to control loops and executes model tensors in the data plane. Draw the boundary around each responsibility instead of labeling an entire product as one plane.

BoundaryControl-plane decisionData-plane actionRequired proof
Edge to routerAuthenticate tenant, normalize policy, assign request IDCarry prompt tokens and sampling requestTenant and request identity are server-issued
Router to prefillSelect compatible worker and reserve prompt capacitySend canonical token IDs to prefillWorker has exact model tuple and deadline budget
Prefill to decodeReserve decode bytes, choose topology, issue transfer IDMove KV blocks and handoff fieldsEvery expected rank and block arrived under same attempt
Decode to frontendGrant one stream ownerEmit token framesCommit succeeded before first visible byte
CleanupExpire lease or close attemptFree blocks and buffersCleanup is idempotent and fenced

This split prevents a common design error. A transport library shouldn't decide tenant authorization, and a global router shouldn't manipulate GPU addresses. Each layer receives the smallest authority needed for its job.

Trace req-8k-017 from router to decode

Keep one immutable identity through the whole path:

FieldValue in running requestWhy it can't drift
Request IDreq-8k-017Joins user-visible outcome, trace, and cleanup
Attempt4Fences late messages from attempts 1 through 3
Tenant isolation keytenant-73Prevents cache and adapter reuse across tenants
Model tuplemodel=m42, tokenizer=t17, adapter=noneDefines token IDs and tensor semantics
Sampling digestsample-9b2Keeps temperature, top-p, stop rules, and seed contract stable
Prompt digesttok-bf81, 8,192 tokensProves prefill and decode refer to same token sequence
KV specification80 layers, 8 KV heads, head dim 128, BF16, block size 16Defines payload shape and byte count
Parallel layoutTP=2, rank map P7:[0,1] to D3:[0,1]Defines which shard each decoder rank must receive

The values describe a fixed teaching model with the same KV shape used in the prerequisite lesson. They aren't a claim about a newly released checkpoint. An actual service should derive this tuple from an immutable deployment manifest, not from client-supplied fields.

1. Authenticate and canonicalize once

The frontend authenticates tenant-73, applies prompt and output limits, assigns req-8k-017, and produces the canonical token sequence. If prefill and decode independently render chat templates, a template or tokenizer mismatch can change token positions even when the visible text looks identical. Current vLLM disaggregated-prefill documentation exposes one way to reuse prefill token IDs at decode through transfer parameters, which makes the identity requirement visible.[1]Reference 1Disaggregated Prefillinghttps://github.com/vllm-project/vllm/blob/main/docs/features/disagg_prefill.md

Canonicalization has one owner. Downstream workers receive token IDs plus a digest and reject an incompatible tokenizer revision.

2. Reserve both phases before expensive work

The router selects prefill worker P7 and decode group D3. P7 has prompt-token capacity. D3 has enough KV bytes, active-sequence slots, and deadline headroom for the expected output.

D3 returns a short-lived reservation for attempt 4. Only then does P7 start the 8K prefill. This ordering is the simplest form of backpressure: downstream scarcity reaches the upstream admission point before compute is spent.

Mooncake's design makes the same systems issue concrete. Its Conductor considers KV placement and prefill/decode load, and its overload policy rejects work early because rejecting after prefill wastes the completed prompt computation.[2]Reference 2Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.https://arxiv.org/abs/2407.00079

Why reserve decode capacity before prefill begins?

Answer

Prefill creates a large, request-specific payload. If no decoder can admit it afterward, the prompt compute and transfer are wasted. A short-lived decode reservation turns downstream capacity into an upstream admission signal.

3. Prefill writes logical KV blocks

P7 processes all 8,192 prompt tokens. It writes 512 logical blocks because each block covers 16 token positions. Under tensor parallelism (TP) of 2, each prefill rank owns its deployed share of every logical block.

Physical block IDs are local allocator details. Prefill rank 0 might store logical block 31 in physical block 904, while decode rank 0 allocates physical block 118 for the same logical range. Correctness requires matching logical positions and shard meaning, not identical physical addresses.

Our request contract gives decode exclusive ownership of user-visible streaming. Prefill returns the prompt KV plus any engine-specific metadata needed to start decode, but the frontend doesn't expose a token until D3 has committed the transfer. Another runtime may divide first-token work differently. Whichever contract you choose, write it down so two components never emit token 1 or advance the sampling state twice.

4. Serialize a manifest, not 2.50 GiB into JSON

Prefill creates a transfer manifest, a small versioned record that describes the payload:

kv-handoff-manifest.json
1{ 2 "request_id": "req-8k-017", 3 "attempt": 4, 4 "transfer_id": "xfer-a91", 5 "tenant_key": "tenant-73", 6 "model": "m42", 7 "tokenizer": "t17", 8 "adapter": null, 9 "prompt_tokens": 8192, 10 "prompt_digest": "tok-bf81", 11 "sampling_digest": "sample-9b2", 12 "kv": { 13 "layers": 80, 14 "kv_heads": 8, 15 "head_dim": 128, 16 "dtype": "bf16", 17 "block_size_tokens": 16, 18 "logical_blocks": 512, 19 "layout_version": "kv-hnd-v3", 20 "tp_size": 2 21 }, 22 "reservation": "d3-lease-772" 23}

The JSON is explanatory, not a portable standard. D3 owns the lease and measures its expiry on a local monotonic clock, so the manifest carries an opaque reservation ID rather than a timestamp or TTL that another host might treat as authoritative. Production metadata also needs backend connection fields and rank-local buffer descriptors. Keep addresses, remote keys, and connection material out of ordinary application logs.

The KV tensor payload stays in registered memory. NVIDIA Inference Transfer Library (NIXL) describes a conductor-managed interface where agents register memory, exchange serialized connection metadata through a side channel or central service, and submit local and remote buffer descriptor lists for asynchronous transfer.[3]Reference 3NVIDIA Inference Transfer Library: Architecture and API Flowhttps://github.com/ai-dynamo/nixl/blob/main/docs/nixl.md That division matters:

ObjectTypical representationRelative sizeOwner
Route intentStructured request metadataKiB-scaleRouter
Transfer manifestVersioned identity, shape, rank, and lease fieldsKiB-scaleHandoff coordinator
Transfer descriptorsRegistered address ranges and backend metadataSmall beside payloadTransfer agents
KV payloadTyped K/V tensors in GPU or staged host memory2.50 GiB herePrefill and decode workers

Turning the whole payload into a language-level byte string adds copies and allocation pressure. A scatter-gather transfer can instead describe the paged regions that already exist. The decode runtime may still need a layout permutation when prefill and decode use different supported tensor layouts. That conversion belongs in a versioned connector contract and in the latency receipt.

5. Move bytes along a measured topology

The transfer layer now moves attempt 4's rank-local KV shards to D3. NIXL is one transport abstraction. It can select among common backends for registered memory types, while the surrounding conductor still owns worker choice, metadata exchange, and failure policy.[3]Reference 3NVIDIA Inference Transfer Library: Architecture and API Flowhttps://github.com/ai-dynamo/nixl/blob/main/docs/nixl.md

NVIDIA Dynamo documents the same separation in its disaggregated flow: a router selects prefill, receives backend-specific transfer metadata, routes decode, and lets NIXL coordinate direct KV movement between worker memory.[4]Reference 4Disaggregated Servinghttps://docs.nvidia.com/dynamo/dev/knowledge-base/concepts/system-architecture/disaggregated-serving Mooncake uses a Conductor for global scheduling and a separate Messenger component for paged KV movement over RDMA (Remote Direct Memory Access), including storage tiers outside GPU memory.[2]Reference 2Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.https://arxiv.org/abs/2407.00079

These are implementations of compatible boundaries, not a ranking:

DesignPlacement and admission ownerKV movement boundaryModel execution boundary
Minimal vLLM splitExternal proxy or routerKV connector, optionally backed by NIXLSeparate vLLM prefill and decode instances[1]Reference 1Disaggregated Prefillinghttps://github.com/vllm-project/vllm/blob/main/docs/features/disagg_prefill.md
NVIDIA DynamoFrontend/router plus worker discoveryBackend transfer metadata and NIXL pathvLLM, SGLang, or TensorRT-LLM workers[4]Reference 4Disaggregated Servinghttps://docs.nvidia.com/dynamo/dev/knowledge-base/concepts/system-architecture/disaggregated-serving
MooncakeConductor and local schedulersMessenger plus distributed KV cacheSeparate prefill and decode pools[2]Reference 2Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.https://arxiv.org/abs/2407.00079

The stable lesson is the interface: decision, movement, and execution need separate contracts. Product names and supported backends will change.

Topology decides whether the split is sensible:

PathLikely movementMain design question
Same acceleratorNo remote handoffWhy split processes if state stays local?
Same fast-link domainGPU-memory transfer over an accelerator fabricCan direct transfer overlap safely with compute?
Same host without fast GPU peer pathGPU copy through PCI Express (PCIe) or staged host memoryDo extra copies erase phase isolation?
Cross-host RDMA fabricRegistered GPU or host buffers over InfiniBand or RDMA over Converged Ethernet (RoCE)Which GPU-to-network-interface route and congestion domain carry each rank?
TCP or remote storage tierStaged or persisted cache chunksIs this reuse path outside first-token critical path?

Don't route only on worker load. A lightly loaded decoder across a weak or congested path can lose to a busier decoder beside the prefiller. Dynamo's topology-aware router documentation explicitly treats rack or zone transfer domains as routing constraints for disaggregated serving.[5]Reference 5Disaggregated Serving: Prefill and Decode Routinghttps://docs.nvidia.com/dynamo/dev/knowledge-base/modular-components/router/disaggregated-serving

6. Commit before decode streams

D3 allocates destination blocks under reservation d3-lease-772, validates the manifest, and waits for all expected rank and block ranges. Partial data stays invisible to attention. When completion arrives, decode performs these checks:

  1. Attempt 4 is still the current fenced attempt for req-8k-017.
  2. Reservation hasn't expired and belongs to tenant-73.
  3. Model, tokenizer, adapter, sampling, KV layout, and TP rank map match.
  4. All 512 logical blocks arrived on every required rank.
  5. Transfer integrity checks and connector completion succeeded.

Only then does the decoder atomically change state from TRANSFERRING to DECODE_READY. It acknowledges the commit, becomes sole stream owner, and releases the prefiller's retained source blocks after the retry window closes.

That commit point is the most important correctness boundary in the data plane. A transport completion means the copy operation finished. A decode commit means the request may consume and expose the received state.

Size the bytes before choosing the fabric

The prerequisite KV lesson gave the payload formula. For each cached token:

Btoken=2×L×Hkv×Dh×PB_{token} = 2 \times L \times H_{kv} \times D_h \times PBtoken​=2×L×Hkv​×Dh​×P

LLL is layer count, HkvH_{kv}Hkv​ is KV-head count, DhD_hDh​ is head dimension, and PPP is bytes per stored value. The leading 2 stores both Key and Value.

For request req-8k-017:

Btoken=2×80×8×128×2=327,680 bytes=320 KiBB_{token} = 2 \times 80 \times 8 \times 128 \times 2 = 327{,}680\text{ bytes} = 320\text{ KiB}Btoken​=2×80×8×128×2=327,680 bytes=320 KiB

Across 8,192 prompt tokens:

Bprompt=327,680×8,192=2,684,354,560 bytes=2.50 GiBB_{prompt} = 327{,}680 \times 8{,}192 = 2{,}684{,}354{,}560\text{ bytes} = 2.50\text{ GiB}Bprompt​=327,680×8,192=2,684,354,560 bytes=2.50 GiB

A 128-token output reservation adds 40 MiB if the same KV shape continues. With TP=2 and ideal KV-head sharding, each rank transfers about 1.25 GiB for the prompt. The two rank transfers still total 2.50 GiB across the model. Replication or layout conversion can raise physical bytes, so inspect actual connector counters instead of dividing blindly by TP.

At block size 16, each global logical block contains 5 MiB of KV payload. There are 512 prompt blocks. Paging changes how those blocks are placed and described; it doesn't shrink their mathematical payload.

Does TP=2 cut the request's total KV transfer from 2.50 GiB to 1.25 GiB?

Answer

Not under ideal sharding. It cuts each rank's shard to about 1.25 GiB, but both shards must arrive, so model-wide transferred payload remains about 2.50 GiB. Replication or conversion can move more.

Transfer time is a budget term

For payload bytes BBB and measured effective payload bandwidth RRR, the no-overlap transfer time is:

Txfer=BRT_{xfer} = \frac{B}{R}Txfer​=RB​

Use effective application payload bandwidth, not a link's marketing line rate. Include registration, staging, layout conversion, queueing, and completion signaling as separate terms when they aren't already inside the measurement.

The runnable exercise keeps the request shape fixed and treats phase timings as an illustrative measurement fixture. It calculates KV bytes, transfer time at three observed payload rates, and one no-overlap time to first token (TTFT) receipt. Replace the timing dictionary with numbers from your trace.

kv-transfer-and-ttft-budget.py
1layers = 80 2kv_heads = 8 3head_dim = 128 4bytes_per_value = 2 5prompt_tokens = 8192 6output_reservation_tokens = 128 7tp_size = 2 8 9bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_value 10prompt_kv_bytes = bytes_per_token * prompt_tokens 11output_reservation_bytes = bytes_per_token * output_reservation_tokens 12 13print(f"KV per token: {bytes_per_token / 1024:.0f} KiB") 14print(f"8K prompt KV: {prompt_kv_bytes / 1024**3:.2f} GiB") 15print(f"TP={tp_size} ideal shard: {prompt_kv_bytes / tp_size / 1024**3:.2f} GiB/rank") 16print(f"128-token output reserve: {output_reservation_bytes / 1024**2:.0f} MiB") 17 18for effective_gb_s in (12.5, 25.0, 50.0): 19 transfer_ms = prompt_kv_bytes / (effective_gb_s * 1e9) * 1000 20 print(f"transfer at {effective_gb_s:4.1f} GB/s: {transfer_ms:6.1f} ms") 21 22measured = { 23 "edge": 6.0, 24 "route_and_reserve": 12.0, 25 "prefill_queue": 18.0, 26 "prefill_compute": 310.0, 27 "manifest": 4.0, 28 "kv_transfer": prompt_kv_bytes / (25.0 * 1e9) * 1000, 29 "decode_queue": 14.0, 30 "commit_and_first_token": 28.0, 31} 32ttft_ms = sum(measured.values()) 33ttft_slo_ms = 650.0 34 35print(f"fixture TTFT: {ttft_ms:.1f} ms") 36print(f"margin to {ttft_slo_ms:.0f} ms SLO: {ttft_slo_ms - ttft_ms:.1f} ms")
Output
1KV per token: 320 KiB 28K prompt KV: 2.50 GiB 3TP=2 ideal shard: 1.25 GiB/rank 4128-token output reserve: 40 MiB 5transfer at 12.5 GB/s: 214.7 ms 6transfer at 25.0 GB/s: 107.4 ms 7transfer at 50.0 GB/s: 53.7 ms 8fixture TTFT: 499.4 ms 9margin to 650 ms SLO: 150.6 ms

The 650 ms target and phase timings are not vendor results. They form a reviewable budget. At the fixture's 25 GB/s effective rate, transfer consumes 107.4 ms and leaves 150.6 ms of margin. If p99 transfer rises by 180 ms under congestion, the request misses TTFT even when prefill compute stays flat.

Layer-wise or chunk-wise transfer can overlap some movement with ongoing prefill. Mooncake describes layer-wise transfer for this purpose, while Dynamo documents non-blocking NIXL movement.[2]Reference 2Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.https://arxiv.org/abs/2407.00079[4]Reference 4Disaggregated Servinghttps://docs.nvidia.com/dynamo/dev/knowledge-base/concepts/system-architecture/disaggregated-serving When work overlaps, don't add both full durations. Trace the critical path and report overlap explicitly:

Thandoff=Tprefill+Txfer−Toverlap+TcommitT_{handoff} = T_{prefill} + T_{xfer} - T_{overlap} + T_{commit}Thandoff​=Tprefill​+Txfer​−Toverlap​+Tcommit​

Overlap doesn't erase bandwidth consumption. It can move waiting time off the critical path while still congesting links used by other requests.

Admission and backpressure need byte credits

Request counts hide the resource that decode must reserve. One 100-token prompt and one 8K prompt both count as one request, but their prompt KV bills differ by roughly 82 times under the same model shape.

Use credits that reflect the constrained resource:

  • Prefill credits: prompt tokens or predicted prefill work inside a deadline window.
  • Transfer credits: bytes in flight per topology domain, with bounded queue age.
  • Decode credits: reserved KV bytes, active sequences, and expected output-token occupancy.
  • Tenant credits: per-tenant prompt, byte, and concurrency limits before shared queues.

Suppose D3 has 8 GiB of uncommitted KV capacity. Each 8K request reserves 2.50 GiB plus 40 MiB for 128 output tokens. Three requests fit under the arithmetic bound. A fourth shouldn't start prefill and hope capacity appears later.

Reservations need a lease. If attempt 4 doesn't commit before its monotonic expiry, D3 returns those credits. A late transfer carrying the old fencing token is discarded. Leases prevent dead workers from pinning capacity; fencing prevents their delayed packets from reviving stale state.

Backpressure flows in one direction even though status flows both ways:

  1. Decode publishes available byte and sequence credits.
  2. Router grants a reservation only while credits and deadline margin remain.
  3. Prefill starts only with a valid reservation.
  4. Transfer queue stops accepting new payloads when its byte or age limit is reached.
  5. Edge rejects or defers work with an explicit retry policy before internal queues become unbounded.

DistServe defines per-GPU goodput as maximum request rate served while meeting a service-level objective (SLO) attainment goal. It applies separate TTFT and decode-latency requirements while choosing resource allocation and placement.[6]Reference 6DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.https://arxiv.org/abs/2401.09670 Raw completed tokens don't count as healthy capacity when their requests miss either user-facing objective.

Why should decode admission use KV bytes rather than only request count?

Answer

Requests have different prompt and output lengths, KV layouts, and precision. Byte reservations represent the memory that must exist after handoff, while a request counter treats a tiny prompt and an 8K prompt as equal.

Routing identity is a correctness protocol

A load balancer can send stateless HTTP traffic to any healthy replica. A disaggregated inference router must select a decoder that can interpret and own existing request state.

Use three identities for different jobs:

  • Request ID: Stable across all attempts. It joins the user operation and idempotency record.
  • Attempt or fencing token: Increases whenever ownership changes. Only highest live attempt may commit or stream.
  • Transfer ID: Names one concrete byte movement. Retransferring same attempt gets a new transfer ID without creating a second stream owner.

Worker compatibility is an exact tuple, not a model family name:

worker-compatibility-tuple.txt
1(model revision, tokenizer revision, adapter revision, 2 KV dtype, KV layout version, block size, 3 layer partition, tensor/pipeline/expert rank map, runtime connector version)

Two groups can both advertise m42 yet disagree on tensor parallel (TP), pipeline parallel (PP), or expert parallel (EP) layout. A connector may support a documented conversion, but the router must select that conversion deliberately and budget its cost. Silent reinterpretation is never a fallback.

Cache locality adds another identity. Prefix hashes must include tenant or sharing scope, model tuple, adapter, and token sequence. A matching token prefix under a different adapter or tenant policy isn't reusable state.

Security starts at the metadata side channel

KV tensors are derived from user prompts and model activations. Treat them as sensitive workload data. Transfer descriptors can also grant access to registered memory regions, so they belong inside the trusted serving boundary.

NIXL's architecture assumes an external conductor handles user requests and exchanges serialized agent metadata through a side channel or central metadata service.[3]Reference 3NVIDIA Inference Transfer Library: Architecture and API Flowhttps://github.com/ai-dynamo/nixl/blob/main/docs/nixl.md That means NIXL is a byte-movement abstraction, not the service's authentication and authorization protocol. The surrounding platform must secure the metadata path.

Build the trust boundary explicitly:

BoundaryThreatRequired control
Client to frontendForged tenant, worker hint, or cache keyAuthenticate caller; ignore untrusted placement fields; stamp tenant server-side
Router to workerRogue or stale worker registrationWorkload identity, authenticated discovery, immutable deployment tuple, short leases
Prefill to decode metadataDescriptor theft, tampering, replayAuthenticated confidential channel, attempt fencing, expiry, manifest integrity
KV payload pathCross-tenant read, corruption, path snoopingIsolated registered regions, protected fabric or encrypted path where required, completion integrity
Cache or storage tierState survives request longer than policy permitsTenant-scoped keys, encryption at rest, retention limit, auditable deletion
TelemetryPrompt, token, descriptor, or adapter leakageRedaction, bounded labels, restricted logs, no raw remote keys

Register the smallest memory pool the connector needs. Bind descriptors to an authenticated worker identity and short attempt lifetime. Revoke or invalidate remote metadata when workers leave or fail; NIXL documents explicit remote-agent invalidation for dynamic removal and failures.[3]Reference 3NVIDIA Inference Transfer Library: Architecture and API Flowhttps://github.com/ai-dynamo/nixl/blob/main/docs/nixl.md

Don't assume RDMA implies encryption or tenant isolation. The deployment owns network segmentation and any confidentiality layer required by its threat model. Measure end-to-end integrity checks instead of adding them blindly. Use authenticated transport integrity and add chunk checks when the connector doesn't provide the required guarantee. Sampled validation belongs in diagnostics, not commit proof; semantic manifest checks stay mandatory.

Failure and retry ownership

Retries are safe only while the protocol knows whether output became visible. The commit gate and first-byte boundary make that decision possible.

Diagram showing Decode bytes reserved, Prefill complete, KV transfer in flight, and Decode commit.
Decode bytes reserved, Prefill complete, KV transfer in flight, and Decode commit.

Before FirstByte, the router can create a new fenced attempt because the client hasn't observed output. After FirstByte, repeating the request may duplicate tokens or side effects in a caller that consumes the stream incrementally. Exact continuation needs an explicit resumable-stream protocol, including output-token position and sampling state. Without one, surface a terminal stream error.

Failure pointState that may existRecovery ownerSafe action
Before reservationRequest envelope onlyFrontend/routerReject, queue within bound, or retry another route
Reservation granted, prefill not startedDecode leaseRouterCancel lease idempotently
Prefill crashesPartial or lost source KVRouterFence old attempt, free lease, choose new prefill
Transfer times out before commitPartial destination blocksDecode then routerDrop partial blocks; retransmit if source is retained, otherwise recompute
Decode reservation expires during transferStale partial stateDecodeReject old fencing token and free destination
Decode crashes before first byteSource may still retain KVRouterStart new attempt or transfer to compatible decoder
Decode crashes after first byteClient has partial outputStream owner/frontendEnd stream with explicit error; resume only under defined protocol
Client cancelsState in both pools and transfer layerFrontend initiates; each owner cleans local stateBroadcast cancellation, stop new work, release idempotently

Retain source KV until decode commit plus a short retry window. Releasing immediately after transport completion removes cheap retransmission. Retaining indefinitely turns prefiller memory into an accidental second cache. The lease and SLO budget should determine the window.

Every cleanup API accepts (request_id, attempt) and succeeds when state is already gone. Idempotency makes duplicate cancellation and delayed failure notices harmless. Fencing makes a late success from attempt 3 unable to delete or commit attempt 4.

Current vLLM KV-transfer configuration makes retry policy explicit with fail and recompute behavior for KV load failures.[7]Reference 7KVTransferConfig API Referencehttps://docs.vllm.ai/en/latest/api/vllm/config/kv_transfer/ Treat that runtime setting as one local mechanism. End-to-end retry ownership still belongs to the service protocol because only it knows whether user-visible streaming began.

A transfer times out after 70% of blocks arrive, but decode hasn't committed or streamed. What happens next?

Answer

Decode discards or quarantines the partial destination under that transfer ID. The router can retransmit from retained source KV or start a fenced recomputation attempt. Decode must never attend to the 70% partial cache.

Observe one request without logging its data

Give req-8k-017 one distributed trace and propagate its server-issued request ID and attempt through every control message. Keep request IDs out of metric labels because their cardinality is unbounded.

Useful spans follow ownership changes:

distributed-request-spans.txt
1frontend.authenticate 2router.select_pair 3decode.reserve 4prefill.queue 5prefill.compute 6handoff.build_manifest 7kv.transfer 8decode.commit 9decode.first_token 10stream.write 11cleanup.release

Each span records safe structural fields: attempt, worker pool, topology domain, model revision, prompt-token bucket, expected and transferred bytes, block count, retry reason, and deadline remaining. It shouldn't record prompt text, raw token IDs, remote memory keys, or full transfer descriptors.

Metrics need phase-specific denominators:

SignalUnit and denominatorWhat it diagnoses
Prefill queue agemilliseconds per admitted prefillPrompt-pool pressure
Decode reservation waitmilliseconds per admitted requestDownstream scarcity before compute
KV payload and wire bytesbytes per transferSharding, replication, compression, or retries
Effective transfer bandwidthcompleted payload bytes per transfer secondTopology and congestion
Handoff successcommitted handoffs / attempted handoffsConnector health
Wasted prefillprefill tokens whose request never commits / all prefill tokensLate admission and failures
Reservation expiryexpiries / granted reservationsLease sizing or transfer delay
Orphaned KV blocksbytes with no live (request, attempt) ownerCleanup correctness
TTFT attainmentrequests within TTFT / completed requestsFull first-token path
Decode attainmentrequests within inter-token or TPOT target / completed requestsStreaming quality

Separate logical payload bytes from physical wire bytes. A retry can move 5.00 GiB for one 2.50 GiB request. Replicated KV heads or a staging copy can also change the ratio. Without both counters, the network bill has no explanation.

Build the SLO from phase budgets

TTFT covers the full critical path until token 1 is visible:

TTFT=Tedge+Troute/reserve+Qp+Tprefill+Thandoff+Qd+Tfirst−tokenTTFT = T_{edge} + T_{route/reserve} + Q_p + T_{prefill} + T_{handoff} + Q_d + T_{first-token}TTFT=Tedge​+Troute/reserve​+Qp​+Tprefill​+Thandoff​+Qd​+Tfirst−token​

After streaming begins, inter-token latency (ITL) belongs mainly to decode scheduling, model execution, and stream flushing. A transfer regression should raise TTFT while leaving steady-state ITL mostly unchanged for successfully committed requests. That symptom is a useful localization clue.

Use an SLO ledger rather than one end-to-end number:

BudgetFixture targetAlert evidenceFirst owner to inspect
Route plus reservation20 msreservation wait p99Router and decode admission
Prefill queue plus compute350 msprompt-token-normalized p99Prefill scheduler
Manifest, transfer, commit150 msbyte-normalized transfer p99Handoff and topology
Decode queue plus first token80 msdecode-admit and first-step p99Decode scheduler
Edge and safety margin50 mstotal TTFT minus traced phasesFrontend or missing span
Total TTFT650 msend-to-end p99 attainmentCross-plane incident owner

These targets match the exercise fixture and remain illustrative. Set production budgets from user experience, then validate them with measured workload distributions. Splitwise and DistServe both motivate phase-specific provisioning because prefill and decode have different resource behavior, while state transfer becomes a new term that placement must minimize.[8]Reference 8Splitwise: Efficient Generative LLM Inference Using Phase Splitting.https://arxiv.org/abs/2311.18677[6]Reference 6DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.https://arxiv.org/abs/2401.09670

Goodput closes the loop: count only offered work that completes inside both first-token and decode objectives. Also report rejection rate. A system can protect latency by rejecting everything, which is healthy backpressure only when the allowed rejection budget says so.

TTFT rises, effective KV-transfer bandwidth falls, and ITL for committed streams stays flat. Which boundary should you inspect first?

Answer

Inspect the prefill-to-decode handoff and its topology. Stable ITL suggests decode execution is healthy after commit, while lower effective transfer bandwidth adds delay before the first token.

Review the contract before scaling it

For req-8k-017, the complete path is now auditable:

  1. Frontend authenticates tenant-73, creates canonical token IDs, and assigns stable request identity.
  2. Router selects compatible P7 and D3, then reserves decode bytes before prefill starts.
  3. Prefill creates 512 logical KV blocks totaling 2.50 GiB across two ranks.
  4. Handoff serializes identity and descriptors while the tensor payload remains in registered memory.
  5. Transfer follows a measured topology and records payload, wire bytes, time, and retries.
  6. Decode validates attempt, layout, completeness, integrity, and lease before one atomic commit.
  7. Decode alone owns user-visible streaming; cancellation and cleanup reach every local owner.

Disaggregation earns its complexity when a tuned mixed pool can't keep both prompt and streaming latency inside their targets, and when the KV handoff fits the remaining first-token budget. DistServe and Splitwise show why separating resource plans can help; Mooncake shows why KV locality, early rejection, and transfer overlap become first-class scheduling concerns.[6]Reference 6DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.https://arxiv.org/abs/2401.09670[8]Reference 8Splitwise: Efficient Generative LLM Inference Using Phase Splitting.https://arxiv.org/abs/2311.18677[2]Reference 2Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.https://arxiv.org/abs/2407.00079

If the mixed pool already meets its SLOs, keep it. The simplest correct data plane has no remote KV handoff. When evidence justifies a split, the design is ready only after bytes, identities, trust, failures, and observability all have named owners.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.For 80 layers, 8 KV heads, head dimension 128, BF16 K/V, and an 8,192-token prompt, what cache payload must the full model hand off?

Correct answer: About 2.50 GiB, with roughly 1.25 GiB per rank under ideal TP=2 sharding.

The per-token payload is 2 x 80 x 8 x 128 x 2 = 327,680 bytes. Multiplying by 8,192 gives 2.50 GiB. Ideal TP=2 sharding divides that across two rank transfers, but both shards are required.

2.Which operation belongs to the control plane rather than the inference data plane?

Correct answer: Authenticating the tenant and issuing a fenced decode reservation.

Authentication, policy, placement, reservation, and retry decisions are control-plane responsibilities. Tensor computation, KV movement, decode, and streaming carry or transform request data in the data plane.

3.Why should a decoder reserve KV bytes before its paired prefiller starts an expensive prompt computation?

Correct answer: It prevents prefill from finishing when no decoder can still admit its KV state.

A decode reservation propagates downstream scarcity upstream before compute is spent. It doesn't guarantee network speed, permit tokenizer drift, or make queues unbounded.

4.What should the handoff layer serialize for req-8k-017?

Correct answer: A versioned manifest and transfer descriptors, while KV tensors remain typed registered buffers.

The manifest carries identity, shape, layout, rank, lease, and completeness information. Buffer descriptors point the transport at registered memory. Serializing the entire tensor payload into JSON would add copies and allocation pressure.

5.The 2.50 GiB payload moves at 25.0 decimal GB/s effective bandwidth with no overlap. Which transfer budget is closest?

Correct answer: About 107 ms, because 2.50 GiB is about 2.684 GB on the decimal-rate denominator.

2,684,354,560 bytes divided by 25 billion bytes per second is about 0.107 seconds. Layer-wise movement may overlap this with prefill, but it doesn't change the payload arithmetic.

6.Prefill worker P7 uses physical block 904 for one logical range, while decode worker D3 allocates block 118 for that range. Is the handoff invalid?

Correct answer: No, if logical token positions, tensor shard meaning, and manifest layout remain consistent.

Physical addresses are local allocator details. The required invariant is that each decode rank maps the same logical token ranges to the correct local shard under the declared layout.

7.A KV transfer times out after 70% of blocks arrive, and the decoder hasn't committed or streamed. Which recovery preserves correctness?

Correct answer: Drop partial state, then retransmit retained KV or start a newly fenced prefill attempt.

Partial state must stay invisible to decode. Before first byte, the router can safely retry under a fenced attempt. Missing blocks can't be treated as zeros or reused by unrelated tenants.

8.Decode crashes after sending 40 output tokens to the client. What is the default safe retry posture without a resumable-stream protocol?

Correct answer: End the stream with an explicit error and avoid blind replay after the first visible byte.

Once output is visible, full replay can duplicate tokens or downstream effects. Exact continuation needs a defined protocol for output position, sampling state, and ownership.

9.Which security design matches a NIXL-style transfer boundary?

Correct answer: Authenticate metadata, bind leased descriptors to worker and attempt identity, and isolate memory regions.

The conductor exchanges connection and memory metadata outside the tensor payload path. That channel and its descriptors need authentication, confidentiality, fencing, expiry, and least-authority memory registration.

10.p99 TTFT rises by 160 ms, KV-transfer bandwidth falls, and ITL remains healthy after streams begin. Which owner should investigate first?

Correct answer: Handoff topology and transfer queue, because delay appears before commit while decode stays healthy.

TTFT includes the prefill-to-decode handoff. Lower effective transfer bandwidth explains extra pre-stream delay, while stable ITL points away from steady-state decode as the first suspect.

10 questions remaining.

Next Step
Continue to Serving Benchmark Engineering

This lesson made every distributed handoff measurable and assigned ownership for bytes, deadlines, failures, and correctness. Next you'll turn those fields into a reproducible load experiment and find the highest request rate that still satisfies the declared serving SLOs.

PreviousGPU Serving & Autoscaling
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Disaggregated Prefilling

vLLM Project · 2026

https://github.com/vllm-project/vllm/blob/main/docs/features/disagg_prefill.md

Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving.

Qin, Y., et al. · 2024

https://arxiv.org/abs/2407.00079

NVIDIA Inference Transfer Library: Architecture and API Flow

NIXL Project · 2026

https://github.com/ai-dynamo/nixl/blob/main/docs/nixl.md

Disaggregated Serving

NVIDIA Dynamo Project · 2026

https://docs.nvidia.com/dynamo/dev/knowledge-base/concepts/system-architecture/disaggregated-serving

Disaggregated Serving: Prefill and Decode Routing

NVIDIA Dynamo Project · 2026

https://docs.nvidia.com/dynamo/dev/knowledge-base/modular-components/router/disaggregated-serving

DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving.

Zhong, Y., et al. · 2024 · OSDI 2024

https://arxiv.org/abs/2401.09670

KVTransferConfig API Reference

vLLM Project · 2026

https://docs.vllm.ai/en/latest/api/vllm/config/kv_transfer/

Splitwise: Efficient Generative LLM Inference Using Phase Splitting.

Patel, P., et al. · 2023

https://arxiv.org/abs/2311.18677

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.