Make the right trade-off / CHAPTER 26
Latency versus throughput
Separate how long one operation takes from how many operations the system completes.
Builds on Back-of-the-envelope estimation.
- Measure response-time distributions rather than averages alone.
- Estimate in-flight work using a stable-system relationship.
- Explain when batching improves capacity but harms waiting time.
01Two different measurements
A report service receives a record, waits for a worker, writes the record and replies. Two measurements describe this differently:
- Latency is the elapsed time for one record from the chosen start to finish. A client-visible measurement includes network travel, waiting and processing.
- Throughput is the number of records actually completed per second. Putting 1,000 records into a queue is not completing 1,000 records.
State what you measured. A CPU timer omits time waiting for storage; requests/s and megabytes/s describe different quantities. Useful capacity is a completion rate that still meets the response-time and error targets.
Also report slow requests. A p99 latency of 300 ms means roughly 99% of measured durations are at or below 300 ms. It is neither the average nor the longest request. Record timeouts and rejected work separately, rather than hiding overload by measuring only fast successful calls.
02Why queues change the result
A queue forms when records arrive before workers can finish them. Follow the work:
- The service accepts a record. It either gives the record to an available worker or puts it in a finite waiting queue.
- A worker processes it. If storage is slow, the worker stays occupied longer and later records wait.
- The finite queue fills, or its oldest record would wait past the promised response time. Ask callers to slow down, or decline new records. These are backpressure and admission control respectively; neither adds processing capacity.
- Measure accepted work until completion. Records still waiting or processing are “in flight.”
For a stable system, Little's Law relates averages: L = λ × W. Average unfinished records L equal completions per second λ multiplied by average seconds in the system W. Measure all three over the same request path. The formula does not use p99 and does not make a continuously growing queue stable.
| Change | Why it might help | What must still be checked? |
|---|---|---|
| Combine records in a batch | One storage operation's fixed cost is shared across records. | The first record waits for others or for a timer. |
| Add workers | Independent records can be processed together. | Workers may compete for the same saturated database. |
| Add queue space | A temporary burst can wait instead of failing immediately. | Waiting grows; processing capacity is unchanged. |
| Decline excess records | Existing work can finish within its promised time. | Callers need a clear retry policy. |
03Worked example: concurrent requests and batching
Assume the service completes 400 records/s and average time from acceptance to completion is 0.25 seconds.
- Calculate unfinished work:
400 × 0.25 = 100records on average. - Storage slows to 0.75 seconds per record at the same completed rate. Average unfinished work becomes
400 × 0.75 = 300. A connection pool with 120 slots cannot contain all 300: some work waits elsewhere, fails, or the completion rate falls. - Arrivals rise to 600/s while completions remain 400/s. The queue grows by about 200 records each second. Ten seconds adds about 2,000 waiting records. Do not apply a stable-system formula to pretend this backlog has stopped growing.
- Bound the waiting. Limit accepted records or slow producers while increasing measured processing capacity. More queue memory alone cannot restore a 250 ms response target.
Now compare storage batches. Assume one record takes 2 ms of storage service, but 100 records together take 20 ms. The ideal service rates are 500 records/s individually and 5,000 records/s in full batches. Those numbers exclude arrival waiting and other bottlenecks.
At ten arrivals/s, the first record would wait nearly ten seconds for a batch of 100. A maximum batch-wait timer releases a partial batch sooner. Measure its actual capacity: partial batches may save less work than full ones.
Latency versus throughput — decision flow
Follow the numbered arrows
- Report clients → Finite waiting queuesubmit records
- Finite waiting queue → Storage workersassign work within worker capacity
- Storage workers → Measure completed workcount completions and elapsed time
- Finite waiting queue → Measure completed workmeasure how long records wait
Trace the diagram in words
- Records join a finite queue and wait for a worker.
- A slowdown keeps each record waiting or processing for longer, increasing unfinished work.
- Measure actual completions, elapsed times and rejected records separately.
04Choose the target that matches the action
Choose the optimization for the actual operation:
- Offline import: a larger batch wait may be acceptable if it reduces total processing cost.
- Interactive write: cap how long the first record waits, and test p99 response time with realistic partial batches.
- More workers: add them only while the database, CPU and connections can support their concurrent work.
- Overload: limit unfinished work rather than accepting an unlimited queue that cannot meet the promise.
For each experiment, use the same payload and arrival pattern. Compare completed records/s, median and p99 latency, rejected records, the oldest queued record's age and resource use.
A useful explanation is: “Storage-call overhead limits completions, so I will batch records but release a partial batch after 10 ms. I will measure its response time and cap unfinished writes when storage slows.” Every part names an action and a reason.
DRAW. CALCULATE. EXPLAIN.
Keep the writer responsive
20 minutes · guided practice
A writer completes 800 records/s at 0.4 s mean end-to-end time. Arrivals then rise to 1,200/s while safe capacity is 900/s. Its batch can hold 50 records and arrivals sometimes fall to 5/s. Calculate concurrency and overload, then choose when to release a partial batch and when to decline excess work.
Compare the worked solution
- Before overload, average unfinished work is 800 × 0.4 = 320 records.
- When 1,200/s arrive and only 900/s can finish, the queue grows by 300 records/s. There is no stable queue size under those rates.
- Ask producers to slow down or decline excess records while adding tested capacity. Measure the age of the oldest waiting record.
- At five arrivals/s, filling a 50-record batch takes roughly ten seconds for the first arrival. Release partial batches with a maximum-wait timer.
- Test the resulting partial-batch completion rate and slow-request latency; full-batch throughput does not establish either.
The checkboxes record your own assessment. The worked solution gives you a way to check the reasoning.
RETRIEVE BEFORE YOU REVEAL
Keep the important ideas.
Say the answer aloud, then turn the card over.
CARD 01How are latency and throughput different?
- Latency measures time for one operation.
- Throughput counts completed operations per unit time.
- State the measured request path and include waiting; accepting a queued job is not completing it.
CARD 02When can you use L = λW?
For a stable system:
- Count completions per second.
- Multiply by average seconds from entry to completion.
- The result is average unfinished work.
Use matching boundaries and averages, not p99.
CARD 03What is batching’s tradeoff?
- Several records share one storage call’s fixed cost.
- Early records wait for others.
- Release partial batches after a maximum wait, then measure their actual completion rate and slow-request latency.
CHECK THE REASONING
Can you explain the choice?
Answer every question, then finish for an immediate score and an explanation for each answer. Aim for 80%, then revisit any gaps.
CLOSE THE LOOP
Explain it without the page.
Summarise the mechanism, one trade-off, and one failure mode. Then mark this chapter complete.