Повторы и таймауты: как настроить их без каскадных сбоев
Повтор запроса помогает пережить краткий сбой, но может перегрузить сервис, который и так не справляется. Разбираем, где ставить таймаут, какие ошибки повторять и как ограничить число попыток, чтобы временная проблема не превратилась в каскадную.

Повторный запрос кажется простым способом пережить сетевой сбой, пока несколько сервисов не начинают повторять его одновременно. Тогда временная перегрузка получает новую волну трафика. Чтобы этого не случилось, задайте общий срок выполнения операции, повторяйте только временные ошибки и ограничивайте суммарное число попыток на всём пути запроса.
Сначала задайте срок всей операции
Таймаут одного сетевого вызова и срок выполнения операции — не одно и то же. Если сервис A ждёт B, а B ждёт C, каждый отдельный вызов может уложиться в свой таймаут, но клиент всё равно будет ждать слишком долго. Поэтому сначала задайте дедлайн1 всей операции, затем распределите оставшееся время между вызовами.
Например, если запросу отведено две секунды, нельзя настроить три последовательных вызова по две секунды каждый. Даже без повторов ожидание превысит срок. При проектировании учитывайте время на обработку, сериализацию ответа и сетевой путь, а не только ожидание удалённого сервиса. Конкретные значения зависят от SLA, распределения задержек и того, сколько времени клиент готов ждать: универсального «правильного таймаута» нет.
Таймаут должен соответствовать ожиданию вызывающей стороны. Если внешний клиент прекращает ждать раньше, чем ваш сервис заканчивает работу, вычисления могут продолжиться впустую. Передавайте оставшееся время вниз по цепочке, если используемый протокол и клиентская библиотека это поддерживают. При этом проверьте их документацию: передача дедлайна устроена по-разному.
Не всякая ошибка заслуживает повтора
Повтор уместен, когда отказ, вероятно, временный: соединение оборвалось, узел недоступен на короткое время, сервис вернул сигнал перегрузки. Ошибка проверки данных, запрет доступа или некорректный запрос сами собой не исправятся. Повторять их — значит тратить ресурсы и скрывать причину.
Важно отличать отказ от неизвестного результата. Клиент мог не получить ответ, хотя сервер уже выполнил операцию. Для чтения это обычно означает, что запрос можно отправить ещё раз. Для списания денег или создания заказа повтор способен создать вторую операцию. Здесь нужна идемпотентность: одинаковый запрос с тем же ключом операции должен приводить к одному результату, а не выполнять действие заново.
Сам ключ не решает задачу автоматически. Сервис должен хранить связь между ключом и результатом достаточно долго, проверять повторное использование ключа с другими параметрами и корректно обрабатывать параллельные запросы с одинаковым ключом. Если такой механизм не предусмотрен, автоматические повторы опасных операций лучше отключить, а результат проверять отдельным запросом или через очередь обработки.
Выберите стратегию повтора
Фиксированная пауза проста, но синхронизирует клиентов: после общего сбоя они могут обратиться снова в один момент. Экспоненциальная задержка постепенно разводит попытки по времени, однако без случайного разброса клиенты всё ещё способны образовать плотные волны. Полный случайный разброс уменьшает синхронизацию, но увеличивает вариативность времени ожидания.
| Подход | Что даёт | Чем платите | Где применить |
|---|---|---|---|
| Фиксированная пауза | Предсказуемое расписание | Повторные запросы могут прийти одновременно | Небольшая система с контролируемым потоком |
| Экспоненциальная задержка без разброса | Увеличивает интервал между попытками | Клиенты с общим стартом могут сохранить синхронность | Ограниченный поток, где нет массового одновременного повтора |
| Экспоненциальная задержка со случайным разбросом | Снижает вероятность повторной волны нагрузки | Время следующей попытки становится менее предсказуемым | Распределённые клиенты и сервисы с параллельными запросами |
В любом варианте ограничьте число попыток и максимальную задержку. Повтор должен помещаться в оставшийся дедлайн; если времени уже не хватает, лучше завершить запрос ошибкой, чем запускать заведомо бесполезную попытку. Не задавайте число попыток как независимую настройку каждой библиотеки: учитывайте все уровни, включая балансировщик, клиентский SDK и вызывающий сервис.
Повтор — это дополнительная нагрузка, а не бесплатная страховка. Если система не может сказать, сколько раз операция уже запускалась и сколько времени осталось, она не контролирует собственный отказ.
Не умножайте попытки по цепочке
Представьте цепочку из трёх сервисов, где каждый делает исходный запрос и ещё два повтора. При неблагоприятном стечении обстоятельств нижний сервис может получить до 27 попыток вместо одной. Это не прогноз для каждой архитектуры, а иллюстрация того, как перемножаются независимые лимиты.
Назначьте одного владельца повторов для конкретного вызова или чётко разделите ответственность между уровнями. Например, клиент может повторять безопасный запрос к одному сервису, но внутренний сервис не должен без ограничений повторять тот же запрос к следующему. Зафиксируйте в документации число попыток, дедлайн, типы ошибок и поведение при его исчерпании. Отдельно проверьте настройки прокси и SDK: скрытый повтор там часто остаётся незамеченным.
Если сервис сообщает, что перегружен, учитывайте предусмотренную протоколом подсказку о времени ожидания, когда она есть. Не трактуйте её как разрешение ждать бесконечно: задержка всё равно должна укладываться в общий дедлайн и локальные ограничения. На практике семантика таких сигналов зависит от конкретного протокола и клиента.
Что ломается при настройке
- Повторяют все ошибки. В результате неверный запрос снова и снова нагружает сервис. Составьте список временных отказов для конкретного клиента, а остальные ошибки возвращайте вызывающей стороне.
- Таймаут слишком короткий. Нормальные медленные ответы превращаются в ошибки и запускают лишние попытки. Сверьте таймаут с измеренным распределением задержек и требованиями к времени ответа.
- Таймаут слишком длинный. Зависшие запросы занимают соединения и рабочие ресурсы. Проверьте, как быстро освобождаются ресурсы при отмене операции и не продолжает ли сервер работу после отказа клиента.
- Нет ограничения общего времени. Несколько повторов с паузами могут пережить срок, который выдерживает пользовательский запрос. Свяжите каждую попытку с оставшимся дедлайном.
- Повторяют запись без защиты. Пользователь получает дубликат заказа или операции. Добавьте идемпотентную обработку либо не повторяйте запрос автоматически.
Как проверить настройки до продакшена
Не оценивайте успех только по доле успешных ответов. Запишите для каждого вызова число попыток, итоговую задержку, причину повтора и факт отмены по дедлайну. Следите за p95 и p99 времени ответа, долей ошибок, количеством одновременных запросов и нагрузкой на нижестоящий сервис. Если после включения повторов ошибок стало меньше, но резко выросли задержка и трафик, система может просто скрывать деградацию ценой перегрузки.
Проверьте как минимум два сценария: сервис отвечает медленно, но в итоге успешно; сервис недоступен дольше, чем общий дедлайн. Отдельно протестируйте неопределённый результат записи: сервер выполнил операцию, но ответ потерялся. Убедитесь, что повтор не создаёт вторую запись. Замеры проводите на той же конфигурации и с похожей конкуренцией запросов, что и в рабочей среде; без этих условий цифры теста мало что говорят о продакшене.
Для выбора стратегии используйте фактические трассировки и метрики, а не одну усреднённую задержку. Сравните, как меняются хвостовые задержки и число попыток при кратком сбое. Повышайте лимит только если видите, что дополнительные попытки действительно успевают завершиться до дедлайна и не ухудшают состояние зависимого сервиса.
Что делать дальше
Возьмите один критичный внешний вызов и опишите его контракт: общий дедлайн, таймаут одной попытки, повторяемые ошибки, максимальное число попыток и гарантию для повторной записи. Затем проверьте, не добавляют ли свои повторы клиентская библиотека и прокси. После этого внесите метрики числа попыток и итогового времени в дашборд и проверьте поведение на отказе зависимости. Настройки для соседних вызовов переносите только после сравнения их задержек и последствий повтора.
1 Дедлайн — крайний момент, к которому операция должна завершиться целиком. В отличие от таймаута отдельного вызова, он ограничивает суммарное ожидание и повторные попытки.
Краткий пересказ книги: О чём книга, кто есть кто, что спросят
Спросить за 10 ₽Источники: Timeouts, retries, and backoff with jitter — Amazon Builders’ Library, Addressing Cascading Failures — Google SRE
Частые вопросы
Сколько повторов ставить по умолчанию?
Можно ли повторять POST-запрос?
Нужно ли повторять запрос, если соединение оборвалось?
Что делать, если сервис вернул ошибку перегрузки?
Как понять, что повторы ухудшили ситуацию?
Нужны ли повторы для каждого сетевого вызова?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.