Resilience4j Fallback и HystrixCommand: повышение устойчивости приложений с помощью примеров кода

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

  1. Резервный режим.
    Механизм возврата позволяет вам определить альтернативное поведение в случае сбоя. Resilience4j предоставляет элегантный способ реализации резервных вариантов с использованием функциональных интерфейсов. Вот пример:
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
@CircuitBreaker(name = "myService")
@RateLimiter(name = "myService")
public String performService() {
    return fallbackMethod();
}
public String fallbackMethod() {
    return "Fallback response";
}
  1. HystrixCommand:
    HystrixCommand — это популярная реализация шаблона автоматического выключателя. Resilience4j интегрируется с HystrixCommand, предлагая аналогичную функциональность. Вот пример использования HystrixCommand:
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.vavr.control.Try;
import org.springframework.web.client.RestTemplate;
@CircuitBreaker(name = "myService")
public String performService() {
    return Try.of(() -> restTemplate.getForObject(serviceUrl, String.class))
              .recover(throwable -> fallbackMethod())
              .get();
}
public String fallbackMethod() {
    return "Fallback response";
}
  1. Прерыватель цепи.
    Resilience4j предоставляет реализацию шаблона прерывателя цепи, которая предотвращает каскадные сбои путем временной остановки вызовов удаленной службы. Вот пример:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .waitDurationInOpenState(Duration.ofMillis(1000))
    .permittedNumberOfCallsInHalfOpenState(3)
    .build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("myService", config);
Supplier<String> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, this::serviceCall);
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> fallbackMethod())
    .get();
  1. Повторить:
    Механизм повтора Resilience4j позволяет автоматически повторять неудачные операции. Вот пример:
RetryConfig config = RetryConfig.custom()
    .maxAttempts(3)
    .waitDuration(Duration.ofMillis(500))
    .retryExceptions(IOException.class)
    .build();
Retry retry = Retry.of("myService", config);
Supplier<String> decoratedSupplier = Retry
    .decorateSupplier(retry, this::serviceCall);
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> fallbackMethod())
    .get();
  1. Bulkhead:
    Шаблон Bulkhead ограничивает количество одновременных вызовов службы, предотвращая перегрузку системы. Resilience4j предлагает реализацию Bulkhead. Вот пример:
BulkheadConfig config = BulkheadConfig.custom()
    .maxConcurrentCalls(10)
    .maxWaitDuration(Duration.ofMillis(100))
    .build();
Bulkhead bulkhead = Bulkhead.of("myService", config);
Supplier<String> decoratedSupplier = Bulkhead
    .decorateSupplier(bulkhead, this::serviceCall);
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> fallbackMethod())
    .get();
  1. Ограничитель скорости:
    Ограничитель скорости Resilience4j позволяет вам ограничить количество вызовов службы в течение определенного периода времени. Вот пример:
RateLimiterConfig config = RateLimiterConfig.custom()
    .limitForPeriod(10)
    .limitRefreshPeriod(Duration.ofSeconds(1))
    .timeoutDuration(Duration.ofMillis(500))
    .build();
RateLimiter rateLimiter = RateLimiter.of("myService", config);
Supplier<String> decoratedSupplier = RateLimiter
    .decorateSupplier(rateLimiter, this::serviceCall);
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> fallbackMethod())
    .get();
  1. Тайм-аут:
    Resilience4j позволяет вам устанавливать тайм-ауты для сервисных вызовов, гарантируя, что они не превысят указанную продолжительность. Вот пример кода для Timeout:
TimeoutConfig config = TimeoutConfig.custom()
    .timeoutDuration(Duration.ofSeconds(5))
    .build();
Timeout timeout = Timeout.of("myService", config);
Supplier<String> decoratedSupplier = Timeout
    .decorateSupplier(timeout, this::serviceCall);
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> fallbackMethod())
    .get();

В этой статье мы рассмотрели несколько методов, предоставляемых Resilience4j, включая резервный вариант, HystrixCommand, автоматический выключатель, повторную попытку, переборку, ограничитель скорости и тайм-аут. Эти функции позволяют создавать отказоустойчивые приложения, способные обрабатывать сбои, смягчать каскадные эффекты и повышать общую стабильность системы. Объединив эти методы с примерами кода, вы сможете использовать возможности Resilience4j и повысить надежность своих Java-приложений.