Fundamentals
Latency budgets
A latency budget splits one end-to-end target across every hop, so each team knows its share. Parallel calls cost the slowest one, and sequential calls add up.
A product requirement might say the home page API responds within 300 ms at p99. That is one number, shared by many services. A latency budget splits it across each hop, so every team knows how much time it can spend and still meet the target.
The big idea
Think of a trip with a fixed travel time. You allocate minutes to each leg. Legs that happen one after another use up the time together. Legs that happen side by side only cost as much as the slowest one.
That gives two rules:
- Parallel calls cost the maximum. Sequential calls cost the sum.
- Keep headroom. A budget with no slack fails on the first garbage-collection pause.
Walking through it
Here is a budget for the home page, with a 300 ms p99 target.
| Hop | p99 budget | Notes |
|---|---|---|
| API gateway and auth | 15 ms | Token checked from a local cache |
| Home service's own work | 35 ms | Serialization and business logic |
| Feed service (parallel) | 150 ms | Fans out itself, so it gets the biggest share |
| Profile service (parallel) | 60 ms | Cached, well under budget |
| Recommendations (parallel, soft) | 120 ms | Dropped from the response if late |
| Headroom | 50 ms | Retries, GC, queueing, and the unexpected |
| Total | 300 ms | Parallel calls cost the max: 15 + 35 + 150 + 50 = 250 ms, under 300 |
The parallel calls don't add up. Feed, profile and recommendations run together, so only the largest one counts. That leaves 50 ms of headroom.
Turning a chain of three 50 ms calls into one parallel fan-out saves 100 ms. Latency goes from 50 + 50 + 50 = 150 ms to max(50, 50, 50) = 50 ms.
Two more rules keep budgets honest:
- Budgets are targets, not proof. Verify the end-to-end latency with measurement and tracing.
- Propagate deadlines. Pass the remaining time along with the request. gRPC does this natively. Then a downstream service can stop working on a request the caller has already given up on.
Common mistakes
- Zero headroom. Budgets with no slack fail on the first slow hop.
- Treating budgets as exact. Percentiles don't add up cleanly, so use budgets to plan and check the total with real traces.
- Forgetting the deadline. A service that keeps working on abandoned requests wastes capacity that live requests need.
Check yourself
- Three 50 ms calls run in sequence. Then they run in parallel. What is the new latency? 50 ms, down from 150 ms, because the parallel calls cost the maximum.
- Why pass the remaining time to downstream services? So they stop work on requests the caller has already given up on.
Key takeaways
- A latency budget splits one end-to-end target across every hop.
- Parallel calls cost the maximum. Sequential calls cost the sum.
- Keep headroom for GC pauses, retries and queueing.
- Propagate deadlines so downstream work stops when the caller gives up.
Further learning
Use observability to measure each hop against its budget, so you can see which team is over.
Next, return to the main availability and latency overview to see how these pages connect.
Related
Tail latency amplification
A request that fans out to many backends waits for the slowest one. With enough fan-out, a rare slow backend becomes the normal response time.
Taming the tail
You can't stop every server from being slow. Set timeouts from measured latency, send a hedged second request when the first is late, and return partial results on time.
Observability: logs and traces
Structured logs, distributed tracing and OpenTelemetry, so you can ask new questions of a running system instead of guessing which dashboard to open.