Latency vs Throughput vs IOPS: why your fast API still fails at scale
EvergreenMany developers optimize an API on latency alone and ignore what happens to throughput under concurrent load. These are different numbers, measuring different things, and a third one (IOPS) matters more than either for storage-bound systems. Knowing which one your application actually lives or dies by is half the work.
The three metrics
- Latency is the time it takes for a single operation to complete.
- IOPS (input/output operations per second) is how many discrete operations the system can complete each second.
- Throughput is the volume of data moved per unit of time.
Latency is about one request. IOPS and throughput are about how many or how much per second - the same distinction as “how long does this trip take” versus “how many cars pass per minute.”
Which metric matters depends on the workload
The right metric to chase is set by the shape of the work, not by preference.
- IOPS-bound work is lots of small, random reads and writes: a system that hits a database constantly, transactional workloads, key lookups. The operation count dominates, so IOPS is the number to watch.
- Throughput-bound work is large or sequential transfers: streaming, backups, analytics scans, media delivery. The data volume dominates, so throughput is the number to watch.
A workload tuned for one can be poison for the other, which is why “make it faster” is never a complete instruction.
Little’s Law ties them together
The three metrics are not independent. Little’s Law says that for any stable system, the average number of requests in flight equals the arrival rate times the average time each one spends inside:
Here is concurrency (requests currently in the system), (lambda) is throughput (arrivals per second), and is latency (time each request spends in the system). Read it as a constraint you cannot cheat. If throughput climbs while latency holds, concurrency must rise - more requests pile up in flight. And if the system caps how many it can hold at once (a thread pool, a connection limit), then pushing throughput up forces latency up instead. This is why a service with a great p50 in a benchmark can fall apart under real load: the benchmark measured at a low , and Little’s Law was waiting.
The slowest requests are what users feel
Averages flatter a system. What a user actually notices is the slow end of the distribution, the P99 and P99.9, and that tail behaves very differently from the median - especially once a request fans out across many internal services. It has its own causes (garbage-collection pauses, queueing, cold caches, distance) and its own defenses (replication, hedged requests, edge caching), so it gets its own note: see Tail latency: the number the average hides.
The bottom line
Throughput and IOPS tell you whether the system keeps up under load, but latency is what a single user actually experiences - so latency should always be on the table, whichever metric you are formally optimizing.
Related
- Performance & Latency MOC - the map these notes hang from
- Tail latency: the number the average hides - where p99 and p99.9 come in
- Queues Are Everywhere - where Little’s Law turns into backpressure
- CPU-bound vs IO-bound - which kind of work sets these limits