JavaRush /Курсы /Модуль 5. Spring /Лекция 234: Реализация Circuit Breaker с использованием R...

Лекция 234: Реализация Circuit Breaker с использованием Resilience4j

Модуль 5. Spring
24 уровень , 3 лекция
Открыта

На прошлых лекциях мы погрузились в мир отказоустойчивости микросервисных систем. Мы обсудили, почему отказы — это не редкость в распределённых системах, как один сбой может вызвать цепную реакцию и повлиять на всю систему, и почему стабильность так важна для хорошего пользовательского опыта. Мы познакомились с паттерном Circuit Breaker, узнали, как он работает, его основные этапы (Closed, Open, Half-Open) и когда его стоит применять. А теперь пора перейти к практике и посмотреть, как внедрить Circuit Breaker в наше приложение с использованием библиотеки Resilience4j.


Что такое Resilience4j?

Resilience4j — это лёгкая, модульная и современная Java-библиотека для реализации различных механизмов отказоустойчивости, включая Circuit Breaker, Retry, Rate Limiter, Bulkhead и другие. Она создана специально для работы с Java 8+ и отлично интегрируется с Spring Boot.

В отличие от более старых решений, таких как Hystrix, Resilience4j имеет минимальный оверхед и поддерживает асинхронные операции из коробки. Почему это важно? В эпоху микросервисов любая лишняя нагрузка на систему может стать причиной проблем.


Почему Resilience4j?

Представьте, что вы выбираете новый смартфон. Что вы хотите? Чтобы был быстрый, не зависал, батарею не сажал и умел всё, что нужно. Вот Resilience4j именно такой:

  1. Легковесность Он как молодой спортсмен — быстрый и эффективный:
  • Минимум лишнего "жира" в зависимостях
  • Экономно использует память
  • Работает быстро, как Усэйн Болт на стометровке
  1. Модульность Как конструктор LEGO — берёте только нужные детали:
  • Подключаете только те функции, которые реально используете
  • Легко встраивается в существующие проекты
  • Настраивается под ваши потребности
  1. Современный подход Идёт в ногу со временем:
  • Дружит с функциональным программированием
  • Поддерживает реактивное программирование
  • Работает на всех современных версиях Java
  1. Spring Boot интеграция Встраивается в Spring Boot как родной:
  • Сам настраивается после подключения
  • Удобные аннотации для быстрого старта
  • Встроенные метрики для мониторинга

Установка и настройка Resilience4j

Шаг 1: Подключение зависимости

Для начала добавим библиотеку Resilience4j в наш проект. Мы будем использовать Gradle, но аналогичная зависимость есть и для Maven.

build.gradle:


dependencies {
    implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.1'
}

Если вы используете Maven, добавьте следующую зависимость:

pom.xml:


<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.7.1</version>
</dependency>

Шаг 2: Базовая конфигурация Circuit Breaker

В Resilience4j для конфигурации Circuit Breaker используется файл application.yml или application.properties. Создадим базовую конфигурацию:

application.yml:


resilience4j.circuitbreaker:
  instances:
    myService:
      registerHealthIndicator: true
      slidingWindowSize: 10
      minimumNumberOfCalls: 5
      failureRateThreshold: 50
      waitDurationInOpenState: 10000

Параметры конфигурации:

  • slidingWindowSize: Количество последних вызовов, которые будут учитываться для оценки состояния.
  • minimumNumberOfCalls: Минимальное число вызовов, чтобы Circuit Breaker начал оценивать состояние.
  • failureRateThreshold: Порог отказов в процентах. Если процент неудачных вызовов превышает этот порог, Circuit Breaker переходит в состояние Open.
  • waitDurationInOpenState: Время (в миллисекундах), которое Circuit Breaker будет оставаться в состоянии Open, прежде чем переключиться в Half-Open.

Практическая реализация Circuit Breaker

Теперь давайте добавим Circuit Breaker в наш сервис. Предположим, у нас есть REST-клиент, который делает вызовы к стороннему сервису.

Шаг 1: Создание REST-клиента

Для упрощения будем использовать RestTemplate. В реальной жизни лучше использовать WebClient (особенно для асинхронных вызовов).

RestClient.java:


@Service
public class RestClient {

    private final RestTemplate restTemplate;

    public RestClient(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public String callExternalService() {
        // Выполняем HTTP-запрос к другому сервису
        return restTemplate.getForObject("http://example.com/api", String.class);
    }
}

Шаг 2: Добавление Circuit Breaker

Теперь оборачиваем наш вызов в Circuit Breaker с помощью аннотации @CircuitBreaker.

MyService.java:


@Service
public class MyService {

    private final RestClient restClient;

    public MyService(RestClient restClient) {
        this.restClient = restClient;
    }

    @CircuitBreaker(name = "myService", fallbackMethod = "fallbackResponse")
    public String process() {
        return restClient.callExternalService();
    }

    // Метод Fallback, который будет вызван в случае срабатывания Circuit Breaker
    public String fallbackResponse(Throwable throwable) {
        return "Fallback response due to: " + throwable.getMessage();
    }
}

Здесь:

  • @CircuitBreaker(name = "myService") связывает наш метод с конфигурацией Circuit Breaker из application.yml (имя myService).
  • fallbackMethod указывает метод, который будет вызван вместо основного, если Circuit Breaker перейдёт в состояние Open или если возникнет ошибка.

Шаг 3: Тестирование поведения Circuit Breaker

Попробуем протестировать наш Circuit Breaker. Для этого симулируем ошибки в сервисе RestClient.

RestClient.java:


public String callExternalService() {
    throw new RuntimeException("Simulated error!");
}

Затем вызовем метод MyService.process() несколько раз (больше, чем minimumNumberOfCalls), и вы увидите, как Circuit Breaker активируется, вызывая метод fallbackResponse.


Настройка параметров Circuit Breaker

Для более тонкой настройки мы можем добавить такие параметры, как метрики времени ответа, лимиты скорости и уведомления. Вот пример расширенной конфигурации:

application.yml:


resilience4j.circuitbreaker:
  instances:
    myService:
      slidingWindowSize: 20
      minimumNumberOfCalls: 10
      failureRateThreshold: 50
      waitDurationInOpenState: 5000
      slowCallRateThreshold: 60
      permittedNumberOfCallsInHalfOpenState: 3
  • slowCallRateThreshold: Порог для "медленных вызовов". Если часть вызовов превышает это время, они считаются "медленными".
  • permittedNumberOfCallsInHalfOpenState: Количество вызовов, разрешённых в состоянии Half-Open для проверки, готовы ли мы переключиться обратно в Closed.

Обзор интеграции с другими механизмами Resilience4j

Resilience4j позволяет комбинировать Circuit Breaker с другими механизмами, такими как Retry и Rate Limiter. Например, вы можете настроить автоматический повтор запросов при временных ошибках:

MyService.java:


@Retry(name = "retryService", fallbackMethod = "fallbackRetry")
@CircuitBreaker(name = "myService", fallbackMethod = "fallbackResponse")
public String processWithRetry() {
    return restClient.callExternalService();
}

В этом случае сначала будет применяться политика повторных запросов (Retry), а затем — Circuit Breaker.


Визуализация состояния Circuit Breaker

Resilience4j предоставляет встроенные метрики для мониторинга состояния Circuit Breaker. Эти метрики можно вывести в Actuator.

application.yml:


management:
  endpoints:
    web:
      exposure:
        include: resilience4j.circuitbreakers

Теперь вы сможете открыть /actuator/resilience4j/circuitbreakers и увидеть текущее состояние Circuit Breaker: сколько вызовов прошло успешно, сколько завершилось ошибкой и сколько вызовов было предотвращено.


Типичные ошибки при использовании Circuit Breaker

  • Забыли настроить fallbackMethod. Без fallback Circuit Breaker не сможет обезопасить вашу систему, и пользователи будут получать необработанные ошибки.
  • Неправильный размер окна (slidingWindowSize). Если размер маленький, это может вызвать ложные срабатывания. Если слишком большой — Circuit Breaker не успеет вовремя реагировать.
  • Игнорирование метрик. Если вы не следите за состоянием Circuit Breaker, то не сможете вовремя скорректировать параметры и улучшить производительность.

Resilience4j и Circuit Breaker — это не просто инструмент, а мощный способ уменьшить влияние отказов одного микросервиса на всю систему. Надеюсь, теперь вы понимаете, как легко можно интегрировать отказоустойчивость в свои приложения. В следующей лекции мы посмотрим на повторные запросы и тайм-ауты. А пока — удачного кодинга и меньше "отказов" в жизни, как в приложениях, так и в коде!

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ