Exponential backoff and jitter calculator

When a call fails, retrying straight away often makes things worse. Set a base delay, a cap and a number of attempts to get the retry schedule for six policies, then watch hundreds of clients retry against a server that was down and is coming back, and see which policy gets them through with the least load.

Attempts
2,429
All done
280 ms
Gave up
0
Retry policy

sleep = random(0, min(cap, base × 2^attempt))

Calls reaching the server per millisecond
server down capacity 200 ms76 ms153 ms229 ms305 ms139
calls (failed ones included) servedEach bar shows the busiest millisecond in a 2 ms window.
Retry schedule
AttemptSleep before itWorst-case total wait
1–0 ms
20 ms to 10 ms10 ms
30 ms to 20 ms30 ms
40 ms to 40 ms70 ms
50 ms to 80 ms150 ms
60 ms to 160 ms310 ms
70 ms to 320 ms630 ms
80 ms to 640 ms1,270 ms
90 ms to 1,000 ms2,270 ms
100 ms to 1,000 ms3,270 ms
Every policy on this outage
PolicyCallsPeak99% done
Immediate (500 gave up)5,0000–
Fixed delay (13 gave up)4,000105103
Exponential3,0131052282
Full jitter2,42925195
Equal jitter2,13140136
Decorrelated jitter1,72319122

Peak is the most calls in one millisecond after the server came back; 99% done is when 99% of the successful clients had their answer.

Failed calls
1,929
Median client done
72 ms
Last client done
280 ms

How to use the calculator

Pick a retry policy and set its base delay, cap and the maximum number of attempts; the schedule table gives the sleep before each retry and the longest a client can spend waiting. The scenario below it runs that policy for many clients at once: each needs one successful call, the server rejects everything while it is down, and afterwards it serves a fixed number of calls per millisecond and rejects the rest. The chart shows the calls arriving each millisecond, and the table on the right runs all six policies on the same outage.

  • Times are in milliseconds and the simulation steps one millisecond at a time. "Rerun with new randomness" draws new jitter and start times.
  • Copy answer gives the schedule and the comparison as text.

Why retries need a strategy

Many failures in distributed systems are brief: a dropped packet, a server restarting, a request that lost a race. Retrying turns these into successes. But when a service fails because it is overloaded, every retry is more load, and clients that retry at once can keep it down long after the original cause has gone.

A retry strategy decides how long to wait before each retry and when to stop. Waiting longer after each failure (backoff) gives the service room to recover; randomising the wait (jitter) stops clients that failed together from retrying together.

Exponential backoff

Exponential backoff doubles the wait after every failure, up to a cap: the sleep before retry k is min(cap, base × 2k). The first retries come quickly, so a brief glitch costs little; a long outage quickly pushes clients to the cap. With a base of 100 ms and a cap of 5 seconds:

AttemptSleep before itTotal waiting so far
1–0 ms
2100 ms100 ms
3200 ms300 ms
4400 ms700 ms
5800 ms1,500 ms
61,600 ms3,100 ms
73,200 ms6,300 ms
85,000 ms11,300 ms

The cap matters as much as the base: without one, the eighth retry would wait 12.8 seconds and the tenth over 51. The total wait is the number to check against a caller’s timeout, since a client that retries for longer than its caller waits is doing work nobody will use.

Jitter

Backoff alone leaves clients synchronised: if a thousand requests fail in the same millisecond, they all retry 100 ms later, then 200 ms after that, in waves as big as the original burst. Marc Brooker’s 2015 AWS Architecture Blog post compared three ways of adding randomness:

  • Full jitter: sleep a random time between 0 and min(cap, base × 2k).
  • Equal jitter: sleep half of that value plus a random time up to the other half, so never less than half.
  • Decorrelated jitter: sleep a random time between the base and three times the previous sleep, capped.

In his simulation of clients contending to update the same database row, plain exponential backoff was the clear loser, doing more work and taking longer than any jittered version. Full and equal jitter made similar numbers of calls, but equal jitter took longer; between full and decorrelated jitter there was no clear winner.

How the policies compare

This page’s simulation asks a different question, recovery from an outage: 500 clients start within 5 ms of each other, the server rejects every call for the first 50 ms, then serves 20 calls per millisecond. Each policy uses a base of 10 ms, a cap of 1,000 ms and up to 10 attempts. Averaged over eight runs:

PolicyCallsGave upBusiest msMedian done99% done
Immediate5,0005000––
Fixed delay4,0001811379 ms103 ms
Exponential3,0190113317 ms2281 ms
Full jitter2,44902174 ms195 ms
Equal jitter2,13103362 ms137 ms
Decorrelated jitter1,71601970 ms125 ms

Immediate retries use up all ten attempts while the server is still down, and every client gives up. A fixed delay keeps hammering in large synchronised waves. Exponential backoff gets everyone through but its waves are as big as the original burst (the busiest millisecond had 113 calls against a capacity of 20), and the unlucky clients end up waiting at the cap, so its 99th percentile is the worst of the policies that succeed. All three jittered policies spread the retries out, finish sooner and make fewer calls. The exact numbers depend on the scenario, which the controls above let you change.

Retry budgets and when not to retry

Backoff limits how fast clients retry, not how much. Google’s Site Reliability Engineering book describes two budgets: at most three attempts per request, after which the failure is passed up to the caller, and a per-client limit that allows retries only while they are under 10% of requests. During an overload the second budget keeps the extra load to about 1.1 times normal, instead of the nearly threefold growth that three attempts per request would allow. The book also warns that retrying at several layers of a stack multiplies the attempts, so retries belong in one layer.

Some calls should not be retried at all. A request that is not idempotent, such as a payment without an idempotency key, may run twice. Errors that will not go away, like a malformed request or a permission failure, should fail fast. And a client that has passed its caller’s deadline should stop.

Retry and backoff questions and answers

How do you calculate exponential backoff?

Multiply a base delay by 2 for every failed attempt and stop growing at a cap: the sleep before retry k is min(cap, base × 2^k). With a base of 100 ms and a cap of 5 seconds the sleeps are 100, 200, 400, 800, 1,600, 3,200, 5,000 ms, and seven retries can take up to 11,300 ms of waiting in total.

Why add jitter to backoff?

Without it, clients that failed together retry together, in synchronised waves that hit the server at the same moment again. In this page’s simulation of 500 clients against a recovering server, plain exponential backoff hit it with up to 113 calls in a single millisecond against a capacity of 20, while full jitter peaked at 21.

What is the difference between full jitter and equal jitter?

Full jitter sleeps a random time between zero and the exponential value; equal jitter always sleeps at least half of it and randomises the other half. Equal jitter never retries very early, at the cost of less spreading. Marc Brooker’s AWS experiments found the two made similar numbers of calls but equal jitter took longer to finish.

What is decorrelated jitter?

A variant in which each sleep is a random value between the base and three times the previous sleep, capped. It grows like exponential backoff on average but each client’s schedule wanders on its own, which spreads retries out well.

How many times should a request be retried?

Few. Google’s SRE book describes a per-request budget of up to three attempts, and a per-client budget that only allows retries while they are under 10% of requests, so a struggling service sees about 1.1 times its normal load instead of nearly 3 times. Retrying at several layers multiplies the attempts, so it is best done in one place.

Further reading

Published Updated