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.
sleep = random(0, min(cap, base × 2^attempt))
| Attempt | Sleep before it | Worst-case total wait |
|---|---|---|
| 1 | – | 0 ms |
| 2 | 0 ms to 10 ms | 10 ms |
| 3 | 0 ms to 20 ms | 30 ms |
| 4 | 0 ms to 40 ms | 70 ms |
| 5 | 0 ms to 80 ms | 150 ms |
| 6 | 0 ms to 160 ms | 310 ms |
| 7 | 0 ms to 320 ms | 630 ms |
| 8 | 0 ms to 640 ms | 1,270 ms |
| 9 | 0 ms to 1,000 ms | 2,270 ms |
| 10 | 0 ms to 1,000 ms | 3,270 ms |
| Policy | Calls | Peak | 99% done |
|---|---|---|---|
| Immediate (500 gave up) | 5,000 | 0 | – |
| Fixed delay (13 gave up) | 4,000 | 105 | 103 |
| Exponential | 3,013 | 105 | 2282 |
| Full jitter | 2,429 | 25 | 195 |
| Equal jitter | 2,131 | 40 | 136 |
| Decorrelated jitter | 1,723 | 19 | 122 |
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:
| Attempt | Sleep before it | Total waiting so far |
|---|---|---|
| 1 | – | 0 ms |
| 2 | 100 ms | 100 ms |
| 3 | 200 ms | 300 ms |
| 4 | 400 ms | 700 ms |
| 5 | 800 ms | 1,500 ms |
| 6 | 1,600 ms | 3,100 ms |
| 7 | 3,200 ms | 6,300 ms |
| 8 | 5,000 ms | 11,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:
| Policy | Calls | Gave up | Busiest ms | Median done | 99% done |
|---|---|---|---|---|---|
| Immediate | 5,000 | 500 | 0 | – | – |
| Fixed delay | 4,000 | 18 | 113 | 79 ms | 103 ms |
| Exponential | 3,019 | 0 | 113 | 317 ms | 2281 ms |
| Full jitter | 2,449 | 0 | 21 | 74 ms | 195 ms |
| Equal jitter | 2,131 | 0 | 33 | 62 ms | 137 ms |
| Decorrelated jitter | 1,716 | 0 | 19 | 70 ms | 125 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.