Подходы и примеры реализации механизма повторных вызовов (retry) в Java
261 открытий2К показов
В крупном Java-проекте с множеством внешних и внутренних API-сервисов, одной из ключевых задач становится надежное получение данных, даже если происходят временные сбои. При активном росте системы и усложнении её архитектуры разработчики используют различные подходы к работе с веб-API — от RestTemplate до GRPC . Однако при таком разнообразии инструментов возникает необходимость внедрить универсальный механизм повторного вызова (retry), который позволяет автоматически повторять запросы в случае ошибок, увеличивая интервал между попытками.
В этой статье мы разберём основные подходы к работе с REST API в Java и рассмотрим популярные библиотеки для реализации retry-механизмов. Я также поделюсь собственным опытом внедрения повторных вызовов с экспоненциальным увеличением задержки между попытками.
Стоит отметить, что далеко не во всех проектах требуется retry, но в нашей системе высокая надёжность — приоритетная задача. Мы работали в распределённой среде, где сервисы активно взаимодействовали друг с другом, а кратковременные сбои в сети могли приводить к сбоям в работе. В таких условиях механизм retry позволял минимизировать потери данных и повысить отказоустойчивость.
Какие ошибки можно решить с помощью retry? В первую очередь, это кратковременные сбои сети и таймауты при ожидании ответа от сервиса. Однако важно понимать, что если сервис перегружен, повторные запросы могут лишь усугубить проблему. В таких случаях необходимо оптимизировать сам сервис, а не полагаться исключительно на retry.
Далее мы рассмотрим, какие библиотеки позволяют реализовать retry в Java, какие стратегии повторных вызовов существуют и как их правильно применять в продакшн-системах.
Использование RetryTemplate с RestTemplate в Spring
RestTemplate — удобный HTTP-клиент в Spring Framework. Хотя он считается устаревшим, его всё ещё активно используют в существующих проектах. Чтобы повысить отказоустойчивость запросов, можно добавить механизм повторных попыток (retry) с использованием RetryTemplate из Spring Retry.
Пример: RestTemplate + RetryTemplate
import org.springframework.retry.policy.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.RestTemplate;
public class RestTemplateRetryExample {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
RetryTemplate retryTemplate = new RetryTemplate();
// Настройка политики повторных вызовов (до 3 попыток)
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3);
retryTemplate.setRetryPolicy(retryPolicy);
// Настройка экспоненциальной задержки между попытками
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(1000); // Начальная задержка 1 секунда
backOffPolicy.setMultiplier(1.1); // Увеличение задержки в 1.1 раза
backOffPolicy.setMaxInterval(10000); // Максимальная задержка 10 секунд
retryTemplate.setBackOffPolicy(backOffPolicy);
String url = "https://example.my.server/api";
try {
String response = retryTemplate.execute(context ->
restTemplate.getForObject(url, String.class)
);
System.out.println("Response: " + response);
} catch (Exception e) {
System.err.println("Request failed: " + e.getMessage());
}
}
}
Использование WebClient с механизмом повторных попыток (retry)
WebClient — современный HTTP-клиент в Spring WebFlux, который поддерживает асинхронные запросы и реактивные потоки. В отличие от RestTemplate, он рассчитан на неблокирующую работу и уже имеет встроенный механизм повторных вызовов.
Использование HttpClient (Java 11+) с механизмом повторных попыток
Начиная с Java 11, стандартная библиотека HttpClient предоставляет мощные возможности для отправки HTTP-запросов, включая асинхронную обработку и гибкие настройки повторных попыток (retry).
Реализация механизма повторных вызовов (Retry) в gRPC
В проекте, где активно используется gRPC наряду с REST API, также возникает необходимость реализовать retry. К счастью, gRPC предоставляет встроенные механизмы обработки повторных запросов, что делает его удобным для высокой надежности системы.
gRPC — высокопроизводительный RPC-фреймворк от Google, основанный на HTTP/2 и использующий бинарный формат данных (Protocol Buffers). Он поддерживает стриминг, асинхронные вызовы и механизмы автоматического повторного запроса при сбоях.
В gRPC механизм retry можно настроить с помощью параметров retryPolicy, передаваемых в ServiceConfig:
import io.grpc.*;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class GrpcRetryExample {
public static void main(String[] args) throws InterruptedException {
// Создаем канал с включенной поддержкой retry
ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", 50005)
.usePlaintext()
.defaultServiceConfig(getServiceConfig()) // Конфигурация retry
.enableRetry() // Включение повторных попыток
.build();
MyServiceGrpc.MyServiceBlockingStub stub = MyServiceGrpc.newBlockingStub(channel);
try {
// Создаем gRPC-запрос
MyServiceClass.MyRequest request = MyServiceClass.MyRequest.newBuilder()
.setMessage("Hello gRPC")
.build();
// Отправляем запрос и обрабатываем ответ
MyServiceClass.MyResponse response = stub.myMethod(request);
System.out.println("Response: " + response.getMessage());
} catch (Exception e) {
System.err.println("RPC failed: " + e.getMessage());
} finally {
// Закрываем канал
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
/**
* Настройка retryPolicy для gRPC
*/
private static Map<String, Object> getServiceConfig() {
return Map.of(
"methodConfig", List.of(
Map.of(
"name", List.of(Map.of("service", "example.MyService")), // gRPC-сервис, для которого применяется конфигурация
"retryPolicy", Map.of(
"maxAttempts", 5, // Максимальное количество попыток
"initialBackoff", "0.1s", // Начальная задержка перед первой повторной попыткой
"maxBackoff", "5s", // Максимальная задержка между попытками
"backoffMultiplier", 2.0, // Увеличение задержки в 2 раза при каждой неудачной попытке
"retryableStatusCodes", List.of("UNAVAILABLE", "DEADLINE_EXCEEDED") // Ошибки, при которых срабатывает retry
)
)
)
);
}
}
Использование gRPC с retry повышает устойчивость микросервисов и делает систему более отказоустойчивой.
Мы рассмотрели несколько популярных подходов для гарантированного получения данных через REST API с использованием Java. Каждый из методов имеет свои преимущества и недостатки, а выбор подходящего решения зависит от конкретных требований проекта. Но стоит помнить, что при применении частых повторных вызовов нагрузка на сервис увеличивается, а ваш проект страдает.
Компания ABBYY уволила всех работников с российскими паспортами, работающих в офисах на Кипре, в Сербии и Венгрии, без объяснения причин. Увольнения прошли быстро, с блокировкой доступа к корпоративным системам
Максим Арокен делится советами с чего начать изучение веб-разработки, как не забросить в самом начале и какую дополнительную технологию изучить, чтобы легче находить заказы на фрилансе.