Какие архитектурные решения повышают надежность вызова REST клиента
Что проверяют
Понимаете ли вы, что удалённый сервис однажды ответит медленно, с ошибкой или не ответит вовсе, и умеете ли не дать этому положить ваш сервис. Следом спрашивают, какие запросы можно повторять и в каком порядке складываются защитные механизмы.
Как отвечать
Начните с того, без чего остальное бессмысленно, и дальше по слоям:
- таймауты: отдельно на установку соединения, на чтение ответа и общий дедлайн запроса. У многих HTTP-клиентов по умолчанию ожидание бесконечное, и один зависший сервис выедает весь пул потоков;
- пул соединений: ограниченный размер и таймаут получения соединения из пула, иначе запросы незаметно копятся в очереди;
- повторы (retry): только на временные сбои (сетевые ошибки,
503,429с учётомRetry-After), с экспоненциальной задержкой и случайным разбросом (jitter). Повторять можно идемпотентные операции, а дляPOSTнужен ключ идемпотентности, который проверяет сервер; - circuit breaker: после серии ошибок перестаёт звать сервис и сразу отдаёт ошибку или fallback, через паузу пропускает пробные запросы (состояния closed, open, half-open);
- bulkhead: отдельный лимит параллельных вызовов на каждого внешнего партнёра, чтобы медленный сервис не занял ресурсы, нужные остальным;
- fallback: кэш последнего ответа, значение по умолчанию или отключение некритичной функции;
- наблюдаемость: метрики латентности и ошибок по каждому клиенту через Micrometer, трассировка с пробросом идентификатора запроса.
Из инструментов назовите Resilience4j (Hystrix давно не развивается), Spring Retry, RestClient или WebClient в Spring и декларативные клиенты через @HttpExchange или OpenFeign.
Где спотыкаются
Повторяют всё подряд, включая POST на списание денег. Один таймаут на медленном ответе превращается в двойную операцию.
Ставят retry на каждом уровне цепочки. Три попытки на каждом из трёх слоёв дают до 27 запросов в упавший сервис, и подняться ему уже не дадут. Отсюда же правило: retry оборачивает circuit breaker снаружи, а не наоборот.
Не задают таймаут и надеются на circuit breaker. Зависший запрос не завершается, и breaker узнаёт о проблеме, когда пул потоков уже исчерпан.