Skip to content
nonconvexcard

Sizing a Serving Cluster End to End

Putting Little's law, the KV-cache budget and the utilisation wall together into a single sizing formula, and reading off which constraint actually binds.

AI SystemsAdvanced⏱ 3 hours8 min readcapacity planningsizingkv cacheconcurrencyheadroom
2 problems →

The three constraints

Fix a replica and a request profile. Write:

  • MkvM_{\text{kv}} — bytes of device memory left for KV cache after weights and workspace;
  • mm — KV bytes for one resident sequence at its expected length;
  • η∈(0,1]\eta \in (0,1] — the fraction of the cache actually usable, after fragmentation;
  • WW — mean end-to-end request latency, the quantity the SLO constrains;
  • λ\lambda — offered load in requests per second for the whole service;
  • ρ⋆\rho^\star — the target utilisation, chosen from the utilisation wall.
PropositionThe memory ceiling on concurrency

The number of requests a replica can hold concurrently is at most

Lmax⁡  =  ⌊η Mkvm⌋.L_{\max} \;=\; \left\lfloor \frac{\eta\,M_{\text{kv}}}{m} \right\rfloor .
PropositionMaximum throughput of one replica
Xreplica  ≤  Lmax⁡W.X_{\text{replica}} \;\le\; \frac{L_{\max}}{W} .
TheoremThe sizing formula

To serve offered load λ\lambda at mean latency WW while keeping each replica at utilisation ρ⋆\rho^\star, the number of replicas required is

  R  =  ⌈λ Wρ⋆ Lmax⁡⌉  =  ⌈λ W mρ⋆ η Mkv⌉  \boxed{\;R \;=\; \left\lceil \frac{\lambda\,W}{\rho^\star\,L_{\max}} \right\rceil \;=\; \left\lceil \frac{\lambda\,W\,m}{\rho^\star\,\eta\,M_{\text{kv}}} \right\rceil \;}

Key idea

Every term in that formula is measurable, and each one is a lever:

LeverEffect on RRHow
mmlinearshorter contexts, grouped-query attention, KV quantisation
η\etainversepaged allocation instead of contiguous reservation
MkvM_{\text{kv}}inversesmaller weights (quantisation), bigger device
WWlinearfaster decode, less queueing
ρ⋆\rho^\starinverseaccept a worse tail

Note that ρ⋆\rho^\star and WW are not independent: raising ρ⋆\rho^\star raises WW through the 1/(1−ρ)1/(1-\rho) factor, so pushing utilisation up buys less than the formula suggests when read naively.

Working an example

Take a replica with Mkv=40M_{\text{kv}} = 40 GB of spare memory, a request profile whose expected KV footprint is m=500m = 500 MB, and paged allocation giving η=0.9\eta = 0.9. Then

Lmax⁡  =  ⌊0.9×40 GB0.5 GB⌋  =  72.L_{\max} \;=\; \left\lfloor \frac{0.9 \times 40\,\text{GB}}{0.5\,\text{GB}} \right\rfloor \;=\; 72 .

With mean latency W=4W = 4 s and target utilisation ρ⋆=0.7\rho^\star = 0.7, one replica sustains 0.7×72/4=12.60.7 \times 72/4 = 12.6 requests per second. Serving λ=500\lambda = 500 requests per second needs

R  =  ⌈500×40.7×72⌉  =  ⌈39.7⌉  =  40 replicas.R \;=\; \left\lceil \frac{500 \times 4}{0.7 \times 72} \right\rceil \;=\; \lceil 39.7 \rceil \;=\; 40 \ \text{replicas} .

Now change one thing. Halving mm — by quantising the KV cache to 8 bits — doubles Lmax⁡L_{\max} to 144144 and halves RR to 2020. Halving WW does the same. Raising ρ⋆\rho^\star from 0.70.7 to 0.90.9 reduces RR to 3131 if WW stayed fixed, but WW does not stay fixed: by the utilisation wall the queueing component grows by a factor (0.9/0.1)/(0.7/0.3)=3.86(0.9/0.1)/(0.7/0.3) = 3.86, and unless queueing was a small part of WW to begin with, the change is a net loss.

Which constraint binds

CorollaryWhich constraint binds

There is a second ceiling on concurrency, from compute: the batch size at which decode stops being weight-bound. Call it LcomputeL_{\text{compute}}. The replica's effective cap is min⁡(Lmax⁡,Lcompute)\min(L_{\max}, L_{\text{compute}}), and:

  • if Lmax⁡<LcomputeL_{\max} < L_{\text{compute}} the replica is memory-bound — buy KV capacity, not FLOPs;
  • if Lcompute<Lmax⁡L_{\text{compute}} < L_{\max} it is compute-bound — a bigger cache buys nothing.

By the decode arithmetic in Inference Arithmetic and the Roofline, arithmetic intensity in weight-limited decoding is 2B/b2B/b for batch BB and bb bytes per parameter, so LcomputeL_{\text{compute}} is roughly the batch at which 2B/b2B/b reaches the hardware's compute-to-bandwidth ratio. For a machine with ratio ≈300\approx 300 and b=2b = 2, that is B≈300B \approx 300. A replica whose memory allows only 7272 concurrent sequences is therefore firmly memory-bound, and its idle arithmetic units are not a bug to be tuned away — they are the direct consequence of the KV budget.

What this does not say

This treats mm and WW as single numbers. Both are distributions, and by the Pollaczek–Khinchine formula their variance affects queueing independently of their means. A profile mixing 200-token and 20,000-token contexts has an mm whose mean badly misrepresents the memory behaviour, because a handful of long sequences can consume the budget that the mean says should hold dozens. Sizing on means and then operating on a mixed workload is a standard way to discover the tail the hard way.

References

These works are cited as sources to read, not reproduced. All exposition, examples and problems on this site are written independently; where an argument is standard, the citation points to a canonical treatment.

Results stated on this page

  • PropositionThe memory ceiling on concurrencyproof includedA replica's KV-cache budget divided by the per-sequence cache size is a hard cap on how many requests it can hold at once.
  • PropositionMaximum throughput of one replicaproof includedCombining the memory ceiling with Little's law bounds a replica's throughput by its concurrency cap divided by request latency.
  • TheoremThe sizing formulaproof includedThe replica count needed is offered load times latency, divided by the product of the concurrency cap and the target utilisation.
  • CorollaryWhich constraint bindsproof includedComparing the memory-limited and compute-limited concurrency caps says whether to buy memory, buy FLOPs, or shorten requests.

Problems (2)

All problems