Короткий ответ
Экспоненциальная задержка увеличивает интервал между попытками по формуле вида base * 2^attempt, а джиттер добавляет случайное отклонение, чтобы множество клиентов не повторяли запрос синхронно в одну и ту же миллисекунду; retry storm возникает, когда много клиентов одновременно и неограниченно ретраят падающий сервис, усиливая нагрузку на него вместо того, чтобы дать ему восстановиться.
Как это работает подробнее
без джиттера все клиенты, упавшие в один момент (например, из-за кратковременного рестарта сервиса), отправят повторный запрос ровно через одинаковый интервал, создавая синхронные "волны" нагрузки; добавление случайной компоненты размазывает повторные запросы во времени.
Пример кода
example-480.py
import time
import random
def retry_with_backoff(func, max_attempts=5, base_delay=0.3, max_delay=10,
retriable_statuses=(429, 500, 502, 503, 504)):
for attempt in range(1, max_attempts + 1):
response = func()
if response.status_code not in retriable_statuses:
return response
retry_after = response.headers.get("Retry-After")
if retry_after:
delay = float(retry_after)
else:
delay = min(max_delay, base_delay * (2 ** (attempt - 1)))
delay += random.uniform(0, delay * 0.1)
if attempt == max_attempts:
return response
time.sleep(delay)Что использовать на практике
- Рекомендация. нужно ограничивать не только число попыток, но и типы ошибок, которые ретраятся — имеет смысл повторять на таймаутах, 502/503/429 и сетевых сбоях, но не на 400/401/403/404, так как повтор того же некорректного запроса ничего не изменит. При получении 429 или 503 с заголовком
Retry-Afterнужно уважать его значение, а не собственную формулу задержки. Для защиты системы в целом ретраи стоит сочетать с circuit breaker, который временно вообще прекращает попытки при длительной недоступности зависимости.
Подводные камни
- Ошибка. ретраить на любой ошибке подряд, включая 4xx-ошибки клиента; не ограничивать максимальное число попыток или максимальное общее время ожидания; каждый затронутый клиент у себя независимо реализует retry поверх retry (например, ретраит сам HTTP-клиент и сверху ретраит вызывающий код), из-за чего реальное число попыток перемножается.