FM5 — Why Your Service Is Slow When Nothing Is Slow

You inspect every service in your call chain. Every one is well within its latency budget. P50 on each is under 30ms. P99 is under 100ms. Nothing looks broken.

Your end-to-end P99 is 800ms and customers are complaining.

This is FM5 — Latency Amplification. None of your individual services is slow. The sum of their latencies is. That arithmetic — fast components producing a slow request — is the most common reason a working system feels broken.

What FM5 Actually Is

A single request triggers multiple sequential downstream calls, each adding latency. The total response time is the sum of all downstream latencies. At P99, this sum can violate the SLO even when each individual call is within budget.

The shape is mechanical:

  • Service A calls B (50ms P99)
  • Service B calls C (50ms P99)
  • Service C calls D (50ms P99)
  • Service D returns

The minimum P99 for a request to A is 150ms — the sum. If each service also takes 20ms of its own processing time, that is another 80ms. The end-to-end is 230ms. Nobody in the chain looks slow. The user waits 230ms anyway.

Fan-out patterns are worse. If A calls B, C, and D in parallel, the response waits for the slowest of them. With three calls each at P99 = 100ms, the wait is not 100ms — it is the maximum of three samples drawn from the latency distribution. The probability that all three are at their P50 is roughly 1 in 8. The probability that at least one is at P99 grows with the number of parallel calls. This is why "tail latency" gets dramatically worse with fan-out.

How It Forms

FM5 is created by synchronous call chains. The deeper the chain, the worse it gets. Three hops is the practical limit before tail latency dominates everything.

The architecture decisions that create it are usually invisible at design time. Each service is small, well-bounded, and within its own latency budget. The system is "well-factored." The user-facing experience is slow because nobody owns the end-to-end budget.

Microservice architectures are especially vulnerable. Every refactor that splits a service into two adds a network hop. A request that used to be in-process becomes RPC. Five years into a microservice migration, requests that used to take 50ms take 600ms — and no individual service is to blame.

How to Detect It

Distributed tracing is the diagnostic tool. A trace captures every span in the call chain — what was called, by whom, for how long. The critical path of the trace shows the latency accumulation: which calls are sequential, which are parallel, where the time is actually going.

The signal: any call chain with more than three synchronous hops is a latency amplification risk at high percentiles. Map your hottest user-facing endpoint. Count the synchronous hops. If the number is greater than three, you have FM5 building up — whether or not it has bitten you yet.

The harder version of the diagnosis is the parallel fan-out case. The trace shows three calls happening at the same time, each within budget. But the wait is the maximum, not the mean. Tail latency on the slowest of N parallel calls is governed by an order statistic. Most monitoring dashboards report each call's P99 individually. Almost none report the max-of-N for a fan-out.

How to Prevent It

Four interventions, ordered by impact:

Parallelise independent downstream calls. If A needs results from B, C, and D and none of them depend on each other, fire them in parallel. Total latency is max(B, C, D), not sum. This is the highest-leverage fix because it costs nothing structurally — just the call site change.

Cache results of expensive calls where freshness permits. A 100ms call that returns the same result for an hour does not need to happen on every request. Cache eliminates the call entirely. This is also where T5 (Caching) overlaps with FM5.

Set per-call timeouts that protect the total budget. If the end-to-end SLO is 500ms and the request makes three calls, no single call can be allowed to take 400ms. The timeout for each call must be a fraction of the total budget. Without per-call timeouts, one slow downstream service consumes the entire latency budget and the system either returns a timeout or — worse — returns nothing while the user waits.

Move non-critical downstream calls to async paths. If a call is needed for the response, it must be on the critical path. If a call is only needed for side effects (analytics, audit logs, notifications), it should be fire-and-forget through a queue. The chapter on Message Queues covers the AT10 tradeoff in detail.

What It Compounds With

FM5 is often a precursor to FM2 (Cascading Failures). When latency amplification brings a service close to its timeout, any further latency increase tips it over into failure. The failure propagates upstream — the caller's thread pool fills waiting for the slow service, the caller times out, and now the caller is failing too. What started as 200ms of accumulated latency becomes a cascading outage.

FM5 also feeds FM7 (Thundering Herd) indirectly. When users see slow responses, they reload. Each reload is another request. The system that was already at its latency limit now has 2× the load. Tail latency gets worse. More users reload. The amplification compounds.

The Diagnostic Question

When investigating a latency complaint, the right first question is not "which service is slow?" — that question presumes a slow component exists. The better question is:

"How many synchronous hops are on this request's critical path, and what is the sum of their P99 latencies?"

If the sum exceeds the SLO and no individual hop violates its own budget, you have FM5. The fix is structural — parallelise, cache, timeout, or async — not per-service optimisation.


FM5 is named in The Engineer's Map — Framework 3 (Book 0, Chapter 7) and applied in depth in Book 3, Chapter 20 — Bulkhead and Timeout Patterns. The book3 chapter walks through the per-call timeout discipline, the bulkhead isolation pattern that prevents one slow dependency from consuming a thread pool, the fallback strategies, and the distributed tracing setup that surfaces FM5 before it tips into a cascading failure.

Read Book 3, Chapter 20 →