Содержимое
У статьи про стажера Васю и идемпотентность, про которую писал тут, оказывается, есть продолжение, в котором Вася разбирается с ретраями — повторными запросами. При идемпотентности такие перезапросы выполнять безопасно. Вот только они могут добить замедлившийся сервер. Хотя статьи эти написаны в первую очередь для разработчиков, аналитикам, особенно проектирующим API, тоже нужно разбираться в теме. Особенно критичной тема перезапросов становится при наличии множества экземпляров клиента (фронтового клиента или клиента-микросервиса) и высокой нагрузки. Если у вас API используется только между двумя экземплярами системы раз в сутки — то вам и заморачиваться особо не нужно (и вообще это больше похоже на ETL, а не на API). Впрочем, в любом случае стоит рассчитывать, что удаленный сервер упадет. Вопросы только — когда и какова будет продолжительность недоступности. Даже если сервер не упадет совсем, а просто замедлится — начнет расти число активных клиентов по Закону Литтла: число клиентов в очереди равно интенсивности запросов умноженное на среднее время обработки запроса. Через некоторое время сервер просто перестанет отвечать: все доступные соединения будут заняты. Если клиент сам обрабатывает запрос другого сервиса — что бывает очень часто в микросервисной архитектуре — задержка начнет распространяться по всей системе в обратную сторону, и ляжет всё. Как сказано в статье от AWS: Рассмотрим систему, в которой вызов пользователя создает пятиуровневый стек вызовов сервиса. Он предусматривает отправку в итоге запроса к базе данных, а также три повторные попытки на каждом уровне. Что происходит, когда в базе данных начинают возникать ошибки запросов вследствие нагрузки? Если на каждом уровне выполняются свои повторные попытки, нагрузка на базу данных увеличится в 243 раза, что сделает ее восстановление маловероятным. Какие моменты в статье про Васю и на что нужно обратить внимание, когда в проектируете перезапросы: 1. Максимальное число перезапросов (в какой-то момент нужно остановиться и выдать ошибку) 2. Промежутки между запросами: равные или увеличивающиеся (exponential backoff)? Кроме экспоненциального роста промежутка бывают ещё увеличивающиеся по последовательности Фибоначчи. 3. Максимальное время, пока мы вообще делаем перезапросы. 4. Jitter — случайная задержка между запросами, чтобы распределить нагрузку от разных экземпляров клиентов. 5. Circuit Breaker — "размыкатель" — отключение ретраев при превышении числа неисполненных запросов определенного порога, например — 20% 6. Retry Budget — на перезапросы выделяется ограниченный "бюджет", доля от общего числа запросов. В статье от AWS упомянут "алгоритм маркерной корзины", который работает примерно так: от каждого успешного запроса клиент "откладывает" в "корзину" часть маркера/токена, например, 0.1. Для того, чтобы сделать перезапрос, клиент должен "взять" из корзины целый токен (соотношение 1/10). Если целых токенов в корзине нет — перезапрос не на что сделать. Также в статье описана техника deadline propagation — когда клиент передает серверу в заголовке запроса значение таймаута, после которого он будет делать ретрай. Если сервер понимает, что не укладывается в таймаут, он сразу прерывает выполнение запроса и возвращает ошибку, причем учитывает ожидание ответа от следующего сервера в цепочке. P.S.: Кроме статьи про ретраи, про Васю есть ещё статья, в которой он проектирует API, там тоже много интересного.