Skip to content

Inference system design chains: demand, replicas, headroom and routing

8 chains

A design round starts with arithmetic that converts traffic into replicas before any box is drawn. These chains follow one method: price each token in replica time by the resource it uses, add up the demand, then divide by what a replica can give under its latency target.

Prefill demand in replica-seconds

inputs   200 requests/s, 2,000 prompt and 300 output tokens each
         Llama 3.3 70B FP8 on TP=4 H100 SXM, 50% MFU assumed for prefill
demand   200 x 2,000 = 400,000 prompt tokens/s; 200 x 300 = 60,000 output tokens/s
per token  2 x 70.55e9 / (4 x 1,979e12 x 0.50) = 35.7 us of replica time
fleet    400,000 x 35.7 us = 14.3 replica-seconds per second
sanity   one 2,000-token prompt is 71 ms of compute before any queueing

Replica-seconds per second is a replica count at 100% busy. Every later step only adds the headroom that latency targets need.

Drilled in: Size the fleet: 70B chat at 200 requests/s · Capacity planning in tokens

Decode work and the TPOT share

inputs   the same replica: 17.6 GB of FP8 weights per GPU, 75% MBU assumed
weights  17.6 GB / (3.35e12 x 0.75) = 7.02 ms per step, whatever the batch
KV       176 MB per sequence per GPU / (3.35e12 x 0.75) = 70 us per sequence
fleet KV 60,000 output tokens/s x 70 us = 4.2 replica-seconds per second
share    at a 50 ms TPOT target, 1 - 7.02 / 50 = 0.86 of each replica is
         left for work that grows with traffic
sanity   the weight read is a fixed tax on every step, paid whatever the load

The weight read is paid once per step and shared by the whole batch. The KV read grows with every running sequence, which is why it counts as demand.

Drilled in: Size the fleet: 70B chat at 200 requests/s

Replicas at a utilization ceiling

inputs   demand 14.3 + 4.2 = 18.5 replica-seconds per second (18.47 unrounded)
         share 0.86 from the TPOT target; a 65% utilization ceiling for bursts
replicas 18.47 / (0.86 x 0.65) = 33.05 -> 34 replicas = 136 GPUs
check    60,000 / 34 = 1,765 output tokens/s per replica, about 27 sequences
sanity   a 1.58x burst takes TPOT to the 50 ms target before anything drops

Round up whole replicas before pricing anything. A fraction of a TP=4 replica cannot be bought.

Drilled in: Size the fleet: 70B chat at 200 requests/s

The prefix-affinity spill rule

inputs   Llama 3.3 70B FP8 on TP=2 H200 SXM, 50% MFU; 8,000-token prompts
         with 6,000 tokens shared per tenant prefix
per token  2 x 70.55e9 / (2 x 1,979e12 x 0.50) = 71.3 us
hit      6,000 x 71.3 us = 428 ms of prefill saved on the warm replica
rule     route to the warm replica unless its queue is more than 428 ms of
         work deeper than the coldest one
sanity   the rule compares prefill work, so affinity and load balance are
         measured in the same unit

Scoring replicas by the prefill work a request would add, queued prompt tokens plus this request's uncached tokens, makes the trade explicit instead of a tuned weight.

Drilled in: Prefix-affinity router with a load spill rule · Prefix-aware routing

Headroom for a cold start

inputs   lead time 1 min to detect + 1 min to schedule + 4 min to load = 6 min
         steepest ramp 1 request/s per minute; 7.39 requests/s per replica
headroom ramp x lead time = 1 x 6 = 6 requests/s = 0.81 replicas
target   ceil((load + 6) / 7.39) replicas
sanity   scaling on a forecast with this headroom ran 520 replica-hours a
         day against 816 for a fleet sized statically at peak

Headroom is set by how fast load rises and how long a replica takes to arrive, not by a percentage chosen in advance. Shorten the load and the headroom shrinks with it.

Drilled in: Autoscale with a four-minute cold start · Autoscaling LLM fleets

Quota units for prompt and output tokens

inputs   Llama 3.3 70B FP8 on TP=4 H100 SXM
prompt   35.7 us of compute per token, as above
output   the KV it reads each step: context x 327,680 B / 4 / 2.51e12 B/s
         = context x 32.6 ns; at 1,700 tokens of context, 55.4 us
weight   55.4 / 35.7 = 1.55 prompt-token units per output token at 1,700;
         context / 1,093 in general, 30 at 32K
sanity   a flat per-token price undercharges long-context output by an
         order of magnitude

Meter tenants in replica time. Counting raw tokens lets a long-context tenant consume many times its share at the same token count.

Drilled in: Multi-tenant quotas and isolation

One long request's share of a pool

inputs   Llama 3.3 70B, 320 KiB of KV per token in BF16; TP=4 H100 pool of
         702,879 tokens
request  131,072 x 327,680 B = 40.0 GiB, 10.7 GB per GPU
share    131,072 / 702,879 = 19% of the replica's pool
sanity   five such requests fill the pool; a per-tenant KV cap is a memory
         limit that rate limits do not provide

Isolation needs a memory limit as well as a rate limit. A tenant within its token quota can still hold a fifth of a replica's cache with one request.

Drilled in: Multi-tenant quotas and isolation

Price per phase from a GPU-hour

inputs   Llama 3.1 8B BF16 on one H100 SXM at an illustrative $2.50 per hour
prefill  2 x 8.03e9 / (989e12 x 0.50) = 32.5 us per token: 30,790 tokens/s
         $2.50 / (30,790 x 3,600) x 1e6 = $0.023 per million input tokens
decode   batch 128 at 1,500 tokens of context: 41.2 GB per step at 75% MBU
         is 16.4 ms, 7,801 tokens/s: $0.089 per million output tokens
ratio    0.089 / 0.023 = 3.9x
sanity   each phase is priced by the resource it saturates: FLOPs for input,
         bytes for output

These are costs at full utilization. Divide by the fleet's average utilization and add the margin before comparing with a list price.

Drilled in: Price an API from a GPU-hour

Next card: Performance Debugging Chains