Throughput and Concurrency
Overview
Section titled “Overview”Capacity planning for an ordinary service starts with requests per second. For inference that is the wrong unit, and using it produces plans that are wrong by orders of magnitude in both directions.
Three properties make this different. None is exotic, and all three are routinely missed.
Concurrency, not requests per second
Section titled “Concurrency, not requests per second”An ordinary request occupies capacity for milliseconds. An inference request occupies it for seconds — and the whole time, it is holding something.
So the unit that matters is how many requests are in flight at once:
graph LR A["Arrival rate<br/><i>requests per second</i>"] --> C["× duration<br/><i>seconds per request</i>"] C --> N["= concurrent<br/>requests in flight"] N --> P["+ headroom<br/>for bursts"] P --> L["Check against the<br/>limit that binds:<br/>quota, or batch capacity"] classDef in fill:#5B8FB9,stroke:#4A7A9E,stroke-width:2px,color:#ffffff classDef calc fill:#E8A33D,stroke:#C4832A,stroke-width:2px,color:#ffffff classDef out fill:#7D9A4E,stroke:#5F7A38,stroke-width:2px,color:#ffffff class A,C in class N,P calc class L out
Arrival rate times duration gives concurrency. It is one multiplication, it takes a minute, and it routinely overturns a capacity plan.
At low arrival rates this number is startlingly small, and the planning instinct — provision for the headline volume — overshoots enormously. At high arrival rates with long responses, it grows faster than people expect, and the same instinct undershoots.
Duration is not known in advance
Section titled “Duration is not known in advance”The second property. Response duration is dominated by output length, and output length is not known when the request arrives.
This gives inference workloads a duration variance unlike a service doing bounded work. A request might take two seconds or forty, and nothing upstream can predict which. Two consequences:
Queueing behaves badly. Long requests block, and tail latency degrades faster than arrival-rate growth alone would suggest. This is the mechanism behind the fat tail Module 2 required you to specify a p95 against.
Caps are structural. A maximum output length is not a stylistic setting; it bounds duration, which bounds concurrency, which bounds the capacity you need. Module 3 called bounding a tactic — this is where the number comes from.
For hosted inference, the limit is somebody else’s
Section titled “For hosted inference, the limit is somebody else’s”The third property, and the one that catches teams who planned carefully against the wrong ceiling.
With hosted inference your constraint is not hardware. It is a quota — typically expressed as requests and tokens per minute — and it is administratively rather than physically bounded. That changes the work:
- Find out the actual limits and whether they are per-minute token budgets, concurrent-request caps, or both. These fail differently.
- Plan for the rejection, not just the steady state. Exceeding a quota returns an error, and that path needs defined behaviour: retry with backoff, degrade a rung down the Module 3 ladder, or queue.
- Negotiate quota ahead of launch. It is a lead-time item with a human in the loop, not a slider.
Self-hosting inverts this: the ceiling is yours and physical, so the planning is familiar, and the trade-off is that running out means buying hardware rather than filing a request.
Batching, and what it trades
Section titled “Batching, and what it trades”Batching processes several requests together, raising throughput substantially on self-hosted accelerators. Its cost is per-request latency: a request may wait for the batch to fill.
That is a direct trade against the latency budget from Module 2 — time to first token, specifically, which is the number users actually judge. Batching is therefore excellent for work with no human waiting (index backfill, evaluation runs, bulk classification) and a poor fit for the interactive path.
Streaming interacts here too. A streamed response holds a connection open for the full generation, so your concurrency figure is also a count of open connections, and any intermediary with its own connection limits becomes part of the capacity picture.
Feeds the workbook
Section titled “Feeds the workbook”Your residency-compliant serving topology needs the concurrency figure and the limit that binds — quota or hardware. Write the multiplication in the document; it is one line and it justifies everything you chose not to build.
→ Capacity is settled by a multiplication. Retrieval quality is settled by a decision most teams make by accident. — Chunking as an architectural decision