При использовании Spring Cloud Feign для связи между микросервисами запросы могут завершиться неудачно из-за проблем с сетью, проблемами сервера и т. д. Для этой ситуации Feign предоставляет механизм повторной попытки, который заключается в повторной отправке запроса, когда запрос не удается, чтобы гарантировать успешное выполнение запроса.
Механизм повторных попыток Feign в основном включает в себя следующие аспекты:
Ниже мы подробно представим эти три аспекта и приведем соответствующие примеры кода.
В Feign мы можем использовать следующие два свойства для настройки количества повторов и интервала повторов:
Среди них clientName — это имя клиента Feign. Мы можем использовать аннотацию @FeignClient в клиентском интерфейсе Feign, чтобы указать имя клиента, как показано ниже:
@FeignClient(name = "user-service")
public interface UserClient {
// ...
}
Далее нам нужно добавить следующие свойства в файл application.yml или application.properties. Например:
feign:
client:
config:
user-service:
retryer: Retryer.Default # Повторитель по умолчанию
retryable: true # Включить условия повтора
another-service:
retryer: Retryer.NEVER_RETRY # Отключить повторные попытки
retryable: false # Отключить условия повтора
В приведенном выше примере мы использовали программу повтора по умолчанию Retryer.Default и включили условия повтора. Это означает, что в случае сбоя запроса Feign автоматически повторит попытку до 5 раз, а интервал повтора по умолчанию составляет 100 миллисекунд. Если нам нужно настроить количество повторов и интервал повторов, мы можем сделать соответствующие настройки в файле конфигурации, например:
feign:
client:
config:
user-service:
retryer: Retryer.Default
retryable: true
maxAttempts: 10 # Повторите попытку до 10 раз.
backoff:
enabled: true # Включить алгоритм отсрочки
delay: 1000 # Начальный интервал повтора составляет 1 секунду.
maxDelay: 5000 # Максимальный интервал повтора — 5 секунд.
multiplier: 2.0 # Интервал повтора увеличивается экспоненциально на 2
В приведенном выше примере мы использовали алгоритм отсрочки по умолчанию, то есть начальный интервал повтора составляет 1 секунду, максимальный интервал повтора составляет 5 секунд, а интервал повтора увеличивается экспоненциально на 2, максимум 10 повторений.
Кроме Настройте количество повторов и интервал Помимо повторов, мы также можем Настроить условия повтора и стратегии повтора.. В Feign мы можем использовать аннотацию @Retryable, чтобы указать условия повтора и стратегии повтора.
Условия повторной попытки обычно включают следующее:
Мы можем использовать аннотацию @Retryable в методах клиентского интерфейса Feign, чтобы указать условия повтора и стратегии повтора. Например:
@FeignClient(name = "user-service")
public interface UserClient {
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
@Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, maxDelay = 5000, multiplier = 2))
User getUser(@PathVariable("id") Long id);
}
В приведенном выше примере мы использовали аннотацию @Retryable, чтобы указать условия повтора и стратегию повтора. В частности, мы указали повторную попытку при возникновении исключения IOException при сбое запроса, до 3 повторов, интервал повтора по умолчанию составляет 1000 миллисекунд, максимальный интервал повтора составляет 5000 миллисекунд, а интервал повтора составляет 2 экспоненциальных роста.
При повторной попытке,Иногда все запросы терпят неудачу. Чтобы этого не произошло,Нам нужно повторить попытку, когда Внедрить резервный механизм повторной попытки,То есть после того, как запрос не выполнен,Постепенно снижайте интенсивность запросов,Избегайте чрезмерной нагрузки на сервис.
В притворстве,Для этого мы можем использовать аннотацию @Fallback. Конкретно,Нам нужно написать резервный класс, реализующий клиентский интерфейс Feign.,Используется для обработки ситуаций, когда запрос не удается. Например:
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
@Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, maxDelay = 5000, multiplier = 2))
User getUser(@PathVariable("id") Long id);
}
@Component
class UserClientFallback implements UserClient {
@Override
public User getUser(Long id) {
// Логика обработки после неудачной попытки
return null;
}
}
В приведенном выше примере мы использовали аннотацию @Fallback, чтобы указать резервный класс UserClientFallback. Если запрос не выполнен, Feign автоматически вызовет метод getUser класса UserClientFallback для обработки. В методе getUser мы можем написать соответствующую логику для обработки ситуации, когда запрос не выполнен, например, возврат значения по умолчанию, ведение журнала и т. д.
Следует отметить, что при использовании аннотации @Fallback мы должны написать запасной класс, реализующий клиентский интерфейс Feign, и реализовать в нем все методы. Это связано с тем, что в Feign каждый метод интерфейса соответствует HTTP-запросу. В случае сбоя запроса Feign необходимо знать, как повторить попытку и отступить. Поэтому мы должны предоставить конкретную реализацию, чтобы сообщить Feign, как выполнять обработку отката.
В то же время мы также можем реализовать более гибкую обработку резервных повторов, реализовав интерфейс FallbackFactory. В частности, интерфейс FallbackFactory позволяет нам внедрить Spring ApplicationContext в резервный класс, чтобы нам было удобнее выполнять некоторые операции, такие как получение информации о конфигурации, вызов других сервисов и т. д. Например:
@FeignClient(name = "user-service", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
@Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, maxDelay = 5000, multiplier = 2))
User getUser(@PathVariable("id") Long id);
}
@Component
class UserClientFallbackFactory implements FallbackFactory<UserClient> {
@Autowired
private ApplicationContext applicationContext;
@Override
public UserClient create(Throwable throwable) {
return new UserClient() {
@Override
public User getUser(Long id) {
// Выберите другую логику обработки в зависимости от типа исключения.
if (throwable instanceof IOException) {
// Обработка IOException
} else {
// Обработка других исключений
}
// Получить клиентские экземпляры других сервисов
OtherServiceClient otherServiceClient = applicationContext.getBean(OtherServiceClient.class);
// Как позвонить в другие службы
otherServiceClient.otherMethod();
// Вернуться к значению по умолчанию
return null;
}
};
}
}
В приведенном выше примере мы реализовали интерфейс FallbackFactory и внедрили Spring ApplicationContext, чтобы мы могли использовать функцию внедрения зависимостей Spring в резервном классе. В методе создания мы можем выбирать другую логику обработки на основе входящего объекта Throwable, получать клиентские экземпляры других сервисов и вызывать их соответствующие методы.