Performance Metrics & Vocabulary - Complete Deep Dive

Prerequisites: Back-of-Envelope Estimation, Terminology Used in: every design — this is the language you use to state and defend non-functional requirements


Why this matters more than it looks

Every system design interview opens with non-functional requirements. Candidates say “it should be fast and scalable.” Strong candidates say “p99 read latency under 200ms at 50K rps, 99.9% availability, and I’ll size the thread pools from Little’s Law.”

Same design, completely different signal. This page is that vocabulary.


Latency vs Response time vs Service time

These three get used interchangeably and they are not the same thing.

        ┌──────────────── response time (what the user feels) ─────────────────┐
        │                                                                     │
client →│ network out │ queue wait │ service time │ serialize │ network back │→ client
        │             └── latency (waiting, not working) ──┘                  │
Term Definition Where you see it
Service time Time actually spent processing Your app’s own timer, server-side histogram
Latency Strictly: time spent waiting (queue + network). Loosely: a synonym for response time. Load balancer metrics
Response time Total client-observed duration RUM, client-side timing, synthetic checks

Say this: “Response time is what the user feels; service time is what my server logs. The gap is queueing — and under load queueing dominates, which is why p99 explodes long before CPU reaches 100%.”

⚠️ The classic gotcha: your server-side p99 is 40ms but users complain. The 40ms excludes queue wait at the LB, TLS handshakes, DNS, and mobile radio wake-up. Always be clear about where you measured.


Latency vs Throughput

Not opposites, and improving one usually costs the other.

Latency    = time per operation     (ms/op)     → lower is better
Throughput = operations per second  (ops/s)     → higher is better
Technique Throughput Latency
Batching (wait to fill a batch) ↑↑ ↑ (you pay the wait)
Pipelining (overlap work) ~
Adding replicas ~ until coordination costs bite
Compression ↑ (less bytes on wire) ↑ CPU, ↓ transfer — net win over WAN, loss over LAN
Caching ↓↓ (the rare win-win)

The highway analogy that actually works: latency is how long your car takes to travel the road. Throughput is how many cars pass per minute. Adding lanes raises throughput without making your trip faster. Raising the speed limit lowers latency. And at high enough traffic, latency degrades even though throughput is at maximum — that’s congestion, and it’s exactly what happens to a saturated service.


Little’s Law — the single most useful formula

L = λ × W

L = average number of requests in the system (concurrency)
λ = arrival rate (requests per second)
W = average time in the system (response time)

Worked example:

10,000 rps × 0.2 s average response time = 2,000 concurrent requests in flight

→ Thread-per-request model needs ~2,000 threads (at ~1MB stack = 2GB just for stacks)
→ Across 20 servers: 100 threads each
→ Each with a 20-connection DB pool: 400 total DB connections — fine
→ If a downstream slows to 1s: L = 10,000 × 1 = 10,000 in flight
  → 500 threads/server needed; pools exhaust; requests queue; p99 collapses
  → An unrelated endpoint on the same pool now times out too

That last line is the whole point. One slow dependency causes a fleet-wide outage through pool exhaustion, and Little’s Law is how you predict it. It’s also the argument for bulkheads (separate pools per dependency) and for aggressive timeouts.

Say this: “I size pools with Little’s Law: at 10K rps and 200ms, that’s 2,000 requests in flight. I’d also set a timeout budget so a slow downstream can’t inflate W without bound — otherwise concurrency grows until the pool exhausts and takes down endpoints that don’t even use that dependency.”


Percentiles — and why averages lie

Metric Meaning Verdict
Average (mean) Sum ÷ count Actively misleading. One 30s timeout hides among thousands of 5ms requests.
p50 / median Half are faster Describes the typical case, says nothing about pain
p90 1 in 10 is slower Where degradation first becomes visible
p99 1 in 100 is slower The standard SLO target. At 10K rps that’s 100 users/second suffering.
p99.9 1 in 1,000 is slower Often your biggest customers — they make the most requests, so they hit the tail most often
max The worst one Useful for spotting timeouts, too noisy for an SLO
Requests (ms): 5, 6, 6, 7, 7, 8, 8, 9, 10, 30000

average = 3,009 ms   ← "our average is 3 seconds!" — nonsense
p50     = 7 ms       ← the truth for typical users
p99     = 30,000 ms  ← the truth for the user who is suffering

⚠️ You cannot average percentiles. Host A’s p99 and host B’s p99 averaged is not the fleet p99. To aggregate you need mergeable structures — histograms with fixed buckets, HDR histograms, or t-digest — then compute the percentile from the merged distribution. This is a genuinely common interview follow-up, and getting it right is a strong signal.

⚠️ Percentiles don’t average over time either. The mean of 60 one-minute p99s is not the hour’s p99.


Tail latency amplification — the fan-out killer

If one request fans out to N services in parallel and waits for all of them, the slowest one determines your response time.

Each service: 99% fast, 1% slow (p99 tail)

N = 1  → P(no slow call) = 0.99      → 1%  of requests are slow
N = 10 → P = 0.99^10  ≈ 0.904        → ~10% of requests are slow
N = 100→ P = 0.99^100 ≈ 0.366        → ~63% of requests are slow (!)

A p99 problem in one service becomes a p37 problem for the user at 100-way fan-out. This is why large-scale systems obsess over tail latency rather than average.

Mitigations, in order of how often they’re the right answer:

Technique How it works Cost
Reduce fan-out Denormalize so one call answers the question Storage, write complexity
Timeouts + partial results Return what arrived in 100ms, degrade the rest Incomplete responses
Hedged requests At p95, send a duplicate to another replica, take the first answer ~5% extra load for a big tail win
Tied requests Send to two replicas; the one that starts cancels the other Slightly more complex
Request budgets Total deadline propagated to every hop; hops that can’t fit fail fast Requires deadline propagation
Avoid sequential hops 5 sequential 20ms hops = 100ms floor before any work Architectural

Say this: “With fan-out I’d worry about tail amplification — 10 parallel calls each with a 1% slow tail means roughly 1 in 10 user requests is slow. I’d propagate a deadline, return partial results past 150ms, and consider hedged requests on the read path where the work is idempotent and cheap.”


Utilization and the queueing wall

The single most counterintuitive fact in performance: queue wait grows non-linearly with utilization and goes vertical near 100%.

For an M/M/1 queue:

Average wait W = S / (1 - ρ)        where S = service time, ρ = utilization

ρ = 50%  →  W = 2 × S       (wait equals service time)
ρ = 80%  →  W = 5 × S
ρ = 90%  →  W = 10 × S
ρ = 95%  →  W = 20 × S
ρ = 99%  →  W = 100 × S     ← the wall
latency
   ↑                                    ║
   │                                   ║
   │                                 ╱
   │                            ╱
   │____________________╱
   └──────────────────────────────────→ utilization
   0%       50%       80%   90%  95% 99%

Practical consequences:


Throughput vocabulary

Term Precise meaning
QPS / RPS Queries/requests per second — a rate. Meaningless for capacity without a latency figure.
TPS Transactions per second. One transaction may be several queries — don’t mix the units.
Concurrency Requests in flight simultaneously (= λ × W). This is what exhausts resources, not the rate.
Bandwidth Theoretical max capacity of the link
Throughput What you actually achieve
Goodput Useful payload delivered, excluding retransmits, headers, and protocol overhead. Under a retry storm, throughput can be high while goodput collapses — a great phrase to have ready.
IOPS I/O operations per second — the disk metric. 4KB random reads is the conventional unit.
Peak vs Average Peak-to-average is typically 2-5× for consumer apps; you provision for peak (plus headroom), you bill on average. Always state which one your number is.

Availability math

The nines

Availability Downtime/year Downtime/month Downtime/week
99% (“two nines”) 3.65 days 7.2 hours 1.68 hours
99.9% (“three nines”) 8.77 hours 43.8 min 10.1 min
99.95% 4.38 hours 21.9 min 5.04 min
99.99% (“four nines”) 52.6 min 4.38 min 1.01 min
99.999% (“five nines”) 5.26 min 26.3 sec 6.05 sec

⚠️ Five nines is less than one bad deploy per year. You cannot reach it with a human in the recovery path — it requires automated failover that’s faster than a page. If you claim five nines in an interview, be ready to justify it.

Serial dependencies multiply

Service chain: gateway → auth → orders → inventory → payments
Each at 99.9%:

0.999^5 = 0.995  →  99.5%  →  1.8 DAYS of downtime per year

This is the strongest technical argument against deep synchronous call chains. Five hops of “very reliable” services produce a mediocre system.

Redundancy adds nines (if failures are independent)

Two independent instances at 99% each:
P(both down) = 0.01 × 0.01 = 0.0001  →  availability 99.99%

⚠️ “Independent” is doing enormous work in that sentence. Same AZ, same deploy, same config push, same certificate expiry, same poisoned cache entry, same dependency — correlated failure eats the benefit. Say this out loud: “redundancy only adds nines to the extent the failures are actually independent, which is why I’d spread across AZs and stagger deploys.”


SLI vs SLO vs SLA vs Error budget

Term Definition Example
SLI — Indicator The measurement ”% of requests served in <300ms, measured at the LB”
SLO — Objective Your internal target “99.9% of requests <300ms over 30 days”
SLA — Agreement The external contract, with penalties “99.5% or you get 10% credit”
Error budget 100% − SLO — the failure you’re allowed 0.1% of 30 days = 43 minutes

Three rules worth knowing:

  1. SLA is always looser than SLO. You need internal headroom before money is at stake.
  2. The error budget is a budget — spend it. Untouched budget means you’re over-investing in reliability and under-investing in features. Exhausted budget means freeze deploys until it recovers.
  3. A good SLI measures the user’s experience, not your server’s comfort. “CPU < 80%” is not an SLI.

Say this: “I’d define the SLO on the user-facing indicator — p99 latency and success rate at the edge — and use the error budget to govern release velocity. That keeps the reliability conversation quantitative instead of ‘the site feels slow.’”


Failure and recovery metrics

Metric Meaning
MTBF Mean Time Between Failures — for repairable systems
MTTF Mean Time To Failure — for non-repairable components (a disk)
MTTD Mean Time To Detect — usually the biggest slice, and the cheapest to improve
MTTA Mean Time To Acknowledge — paging and on-call health
MTTR Mean Time To Repair/Recover
Availability = MTBF / (MTBF + MTTR)

The insight: halving MTTR improves availability exactly as much as doubling MTBF — and it’s usually 10× cheaper. Better alerting, faster rollback, and rehearsed runbooks beat heroic engineering to prevent all failure.

  RPO RTO
Question How much data can I lose? How long can I be down?
Set by Backup/replication frequency Recovery process speed
RPO = 0 Synchronous replication (latency cost)
RTO = 0 Active-active with automatic failover

Latency numbers to have memorized

Operation Time Relative
L1 cache reference 1 ns
L2 cache reference 4 ns
Branch mispredict 3 ns
Mutex lock/unlock 17 ns
Main memory reference 100 ns 100×
Compress 1KB (snappy) 2 μs
Read 1MB sequentially from RAM 3 μs
SSD random read 16 μs 16,000×
Read 1MB sequentially from SSD 49 μs
Round trip within same datacenter 500 μs
HDD seek 2 ms 2,000,000×
Read 1MB sequentially from HDD 825 μs
Round trip India ↔ US East ~200 ms

The three ratios that actually matter in an interview:


Interview application

Stating non-functional requirements: “Reads: p99 < 200ms at 50K rps. Writes: p99 < 500ms at 5K rps. Availability 99.9% for reads, 99.99% for the payment path. Consistency: strong for balances, eventual (< 2s) for feeds. Peak-to-average 3×, so I’ll provision for 150K rps read capacity with 30% headroom.”

Defending a design: “I keep the read path to two hops because five 99.9% services in series is 99.5% — a day and a half of downtime a year. Anything not on the critical path moves to async via a queue.”

Sizing: “At 50K rps with 40ms service time, Little’s Law gives 2,000 concurrent requests. With 200 concurrent per instance that’s 10 instances, and I’d run 15 for headroom and AZ loss tolerance.”


Common Interview Questions

Q: “What latency should we target?” A: “Depends on the interaction. Under 100ms feels instant; 100-300ms feels responsive; past 1s users notice and start abandoning. I’d set p99 < 200ms for the read path and be explicit that I’m measuring at the edge, not server-side.”

Q: “Why p99 and not average?” A: “Averages hide the tail — one 30s timeout disappears into thousands of 5ms requests. At 10K rps, p99 is 100 users every second having a bad experience. And with fan-out, a 1% tail per service becomes a 10% tail for the user across 10 parallel calls.”

Q: “How do you compute p99 across 50 servers?” A: “You can’t average their p99s. Each host exports a histogram (or t-digest), you merge the distributions centrally, then compute the percentile. Averaging percentiles is a common and wrong shortcut.”

Q: “Your CPU is at 70% and latency is bad. Why?” A: “Queueing. At 70% utilization average wait is already about 2.3× service time, and the curve is non-linear — bursty arrivals put you briefly at 95%+ where wait is 20× service time. Also check whether you’re actually CPU-bound: lock contention, GC pauses, or a saturated connection pool all produce latency at moderate CPU.”

Q: “Latency vs throughput — can you have both?” A: “Caching gives you both. Almost everything else trades: batching raises throughput and hurts latency, and adding capacity raises throughput without changing per-request latency. The one thing that helps both is removing work — fewer hops, fewer bytes, fewer round trips.”

Q: “How much capacity do you provision?” A: “Peak, not average — typically 2-5× average for consumer traffic — targeting 60-70% utilization at peak so I stay off the vertical part of the queueing curve, plus enough spare that losing an AZ doesn’t push the survivors past that line.”

Q: “What’s the difference between an SLO and an SLA?” A: “SLO is the internal target, SLA is the contractual promise with penalties. The SLO is always stricter, so you find out you’re in trouble before your customers get a credit.”


Decision Framework

Question Metric to reach for
Is the system fast enough for users? p99 response time at the edge
Can it handle the load? Throughput at target p99 (not max throughput)
How many threads / connections? Little’s Law: L = λ × W
How much headroom? Keep peak utilization ≤ 70%
How reliable must this be? SLO + error budget, then check serial-dependency math
How fast must we recover? RTO; and improve MTTD/MTTR before MTBF
How much data can we lose? RPO → replication mode
Why is the tail bad? Fan-out width, queueing, GC pauses, lock contention

← Back to Fundamentals ← Transactions & Isolation Next: Networking Basics →

Free system design + DSA prep. If it helped you crack an interview, consider supporting.