Hedged Requests Cut Tail Latency at a Capacity Cost
A service can have acceptable median latency while a small fraction of requests take much longer. Queueing, a cold cache, runtime pauses, transient packet loss, or a slow storage operation can leave one attempt far behind the normal path. At sufficient fan-out, those rare delays become common at the aggregate request boundary.
A hedged request starts a second equivalent attempt after the first has remained incomplete for a selected delay. The caller accepts the first useful result and cancels or discards the other attempt.
time --->
attempt A: |---------------------- result
hedge: |------ result
^
hedge delay
caller returns the hedge resultThis is controlled redundancy, not an ordinary retry after failure. The original attempt may still be healthy; it is merely late relative to the service’s latency target.
The delay controls the work-latency tradeoff
Sending two attempts immediately can reduce latency, but it also doubles request pressure for every operation. A hedge delay avoids duplicate work for requests that complete within the normal latency range.
A common policy derives the delay from a recent latency percentile for the same operation class. If the hedge starts near the point where an attempt has become unusually slow, only a minority of calls create duplicates.
if first attempt completes before hedge_delay:
return first result
start second attempt
return first acceptable result
cancel the remaining attemptA fixed delay can also be appropriate when the service has a stable latency budget. The value still needs measurement against current traffic because queueing and dependency behavior can shift over time.
The useful metric is not only the reduction in a high percentile. The system also needs the hedge rate, additional backend operations, cancellation effectiveness, and latency of both winning and losing attempts.
Duplicate attempts need equivalent semantics
Both attempts must represent the same logical read or operation. Hedging is straightforward for side-effect-free reads because either result can satisfy the caller when both target an acceptable consistency boundary.
Mutations require much stricter treatment. Issuing two writes can duplicate a charge, reservation, message, or state transition. A mutation can only be hedged when its protocol already provides a safe operation identity and deduplication boundary appropriate to concurrent attempts.
Even reads may not be interchangeable across replicas. If one attempt reads from a leader and another from a lagging replica, the first response may not satisfy the consistency contract expected by the caller. Replica selection therefore belongs to the hedge policy rather than being an arbitrary routing choice.
Cancellation limits waste but does not erase it
Once one attempt wins, the caller should cancel the loser when the transport and server support useful cancellation. That signal can release a connection slot, stop downstream work, or prevent a queued operation from starting.
Cancellation is not rollback. The losing request may already have consumed CPU, issued a database query, filled a cache entry, or completed work before the cancellation arrives.
attempt A -> service -> database query
attempt B -> service -> database query
|
+-- wins
cancel AThe database operation from A may still continue if cancellation does not propagate through that boundary. Capacity accounting must therefore use observed work rather than assuming every canceled attempt became free.
A request deadline remains important. Both attempts should stay inside the original caller budget; the hedge must not create a fresh lifetime that outlives the operation it serves.
Correlated slowness reduces the benefit
Hedging helps most when the second attempt can avoid the condition slowing the first. Sending both attempts through the same congested queue, process, shard, or network path can reproduce the same delay.
Replica diversity can improve independence:
caller
|---- attempt A ---> replica 1
|
+---- hedge -------> replica 2Diversity is not automatically beneficial. A second replica may have colder data, lower capacity, or different consistency properties. Cross-zone routing may add network cost. A policy needs to respect placement, affinity, cache locality, and data ownership.
System-wide incidents also make attempts highly correlated. When every backend is saturated, extra hedges can add pressure without producing a faster path.
Overload protection must account for hedges
A hedge policy that ignores saturation can form a positive feedback loop. Latency rises under load, more requests cross the hedge threshold, duplicate traffic rises, and the extra traffic pushes latency higher.
The admission path should count hedges as real work. Concurrency limits, load shedding, and per-client budgets can restrict duplicate attempts when spare capacity disappears.
One practical control is a hedge budget: only a bounded fraction of primary traffic may create concurrent duplicates over a measurement window. Another is to disable or delay hedging when backend queue depth or utilization crosses a threshold.
These controls preserve the central assumption behind hedging: spare capacity is being exchanged for lower tail latency. When spare capacity is absent, that exchange no longer has the same economics.
Request classes need separate policies
A single percentile across all traffic can produce a poor hedge delay. Fast cache reads, large object reads, and expensive analytical queries may have very different latency distributions and resource costs.
Policies can be partitioned by endpoint, operation type, payload class, tenant tier, or another stable workload dimension. The partition should be coarse enough to maintain useful measurements while separating materially different service behavior.
Hedging very expensive work deserves a higher bar because one duplicate can consume substantial capacity. Cheap reads with independent replicas may tolerate a more aggressive policy.
Metrics must separate primary and duplicate work
Aggregate latency alone can hide the cost of the technique. Telemetry should identify primary attempts, hedge attempts, winners, losers, cancellations, and attempts that continued after cancellation.
Useful ratios include:
hedge rate = hedged logical requests / logical requests
hedge win rate = hedge winners / hedge attempts
extra work = backend attempt work / logical request workA high hedge rate with a low hedge win rate often indicates that the delay is too aggressive or that duplicate paths are strongly correlated. A high win rate can still be unhealthy if the extra traffic drives backend saturation.
Tracing benefits from one logical operation identifier shared by both attempts plus a distinct attempt identifier for each branch. That preserves the relationship without merging two physical executions into one span.
Tail reduction is conditional on spare, independent capacity
Hedged requests can turn occasional slow attempts into faster logical responses when another execution path has a good chance of finishing sooner. The mechanism does not make a slow backend faster and does not remove the resource cost of duplicated work.
The policy is strongest when attempts are semantically interchangeable, duplicate paths have some independence, cancellation propagates far enough to save work, and overload controls can suppress hedges during saturation. Under those conditions, a delayed duplicate can tighten the latency tail without making duplicate execution the default path.