В какой-то момент почти любой сервис начинает ловить таймауты к соседям. Где-то сеть моргнула, где-то зависла база, где-то просто не повезло.
Первая реакция обычно максимально логичная: добавим пару ретраев и станет стабильнее
Не ответил на запрос - попробуем ещё раз. Если всё идемпотентно, то вообще без риска. Но как только одному из сервисов становится реально плохо, вся эта история начинает работать в обратную сторону
👀 Представь обычную цепочку: Order Service ходит в Payment Service. Платёжка начала тормозить, не умерла, но отвечает по 3–5 секунд, а потом вообще перестаёт. Order такой:
«Окей, не ответил - попробую ещё раз, не получится, то повторю снова»
И так делает не один запрос, а сразу вся система. В этот момент ретраи превращаются из «страховки» в «давай добьём всё окончательно»
Нагрузка растёт → сервис отвечает ещё медленнее → растёт количество таймаутов → таймауты рождают новые ретраи🫢 Классический замкнутый круг, где система сама себе ухудшает состояние. Обычно в этот момент вспоминают про
exponential backoff. Типа не долбим сразу, а ждём: сначала секунду, потом две, потом четыре. Плюс добавляем jitter, чтобы все клиенты не проснулись одновременно и не прилетели в одну и ту же миллисекундуЭто действительно лучше. Но есть одна неприятная деталь, о которой редко думают: Backoff не уменьшает нагрузку, он её откладывает
Если сервис быстро восстановился - всё красиво, запросы разъехались по времени и он успел их переварить.
Но если даунтайм длинный, то все эти отложенные ретраи всё равно прилетят. Просто чуть позже и более плотной волной
И вот ты уже в ситуации, где баг пофиксили, релиз откатили, а система всё равно не оживает 😐
Потому что на неё одновременно падает обычный трафик, накопленные ретраи и ещё пользователи, которые сами жмут «повторить». Сервис снова захлёбывается, ловит таймауты, генерит новые ретраи - и поехали по второму кругу
🤔 Это то самое состояние, когда триггер уже убрали, а система всё равно не может восстановиться, потому что сама себя держит под нагрузкой. В этот момент приходит довольно неприятное осознание:
ретраи - это не всегда про надёжность.
Иногда это про то, как замедлить восстановление в несколько раз
🟣И один из нормальных подходов - retry budget
Идея простая: ретраи разрешены, но ограничены, например, не больше 10% от успешных запросов. Пока сервис отвечает нормально, бюджет есть, можно ретраить флапы. Как только он начинает сыпаться, успешных ответов становится мало, бюджет быстро заканчивается, и ты автоматически перестаёшь накидывать сверху дополнительную нагрузку
❗️Иногда это дополняют retry circuit breaker’ом - если процент ошибок слишком высокий, ретраи временно вырубаются вообще. Потому что в этот момент лучше быстро получить ошибку, чем ещё сильнее убить сервис и затянуть восстановление.
И тут важно понять, retry - это нагрузка, которую ты берёшь в долг у системы. Пока всё хорошо - это почти незаметно и даже полезно. Когда всё плохо - этот долг внезапно приходит с процентами.
🆗 Поэтому хороший retry - это всегда про ограничения, контроль и понимание, в каком состоянии находится сервис.
❌ А плохой retry - это когда система уже лежит, а ты продолжаешь верить, что следующая попытка точно сработает
Накидай 🔥, если было полезно 😎
