Вопрос проверяет знание методов построения устойчивых систем, когда отказ одного микросервиса не должен приводить к каскадному отказу всей системы.
Отказоустойчивость достигается за счет обработки ошибок на уровне кода (try-catch, возврат понятных клиенту ошибок) и применения специальных паттернов, таких как механизмы повтора (retry) для временных сбоев и Circuit Breaker ("предохранитель") для защиты от повторяющихся вызовов к неработающему сервису. Это предотвращает накопление запросов и "зависание" системы.
В мире микросервисов сетевые сбои, временная недоступность сервисов и медленные ответы — это норма. Система должна быть готова к ним.
Методы обеспечения отказоустойчивости:
Грамотная обработка исключений:
Каждый вызов другого сервиса должен быть обернут в обработку исключений.
Клиенту (другому сервису или фронтенду) должен возвращаться понятный HTTP-статус (например, 503 Service Unavailable) и структура ошибки.
Таймауты (Timeouts):
Обязательная установка таймаутов на подключение (connection timeout) и чтение (read timeout) при выполнении HTTP-вызовов. Это не дает запросам "висеть" вечно.
Паттерны повышения устойчивости: Они часто реализуются с помощью библиотек (Resilience4j).
Retry (Повтор): Автоматически повторяет вызов при временной ошибке (например, Network error).
Circuit Breaker (Предохранитель): Следит за процентом неудачных вызовов.
Пример обработки в коде (псевдо-код с Resilience4j):
@Service
public class OrderService {
private final PaymentServiceClient paymentClient;
private final CircuitBreaker circuitBreaker;
private final Retry retry;
public OrderService(...) {
// Конфигурация Circuit Breaker: размыкаться после 50% ошибок в скользящем окне из 100 вызовов
circuitBreaker = CircuitBreaker.ofDefaults("paymentService");
// Конфигурация Retry: 3 попытки с экспоненциальной задержкой
retry = Retry.ofDefaults("paymentService");
}
public void processPayment(Order order) {
// Объединяем паттерны: сначала Retry, и если он не помог, Circuit Breaker фиксирует ошибку
Supplier<PaymentResponse> decoratedSupplier = CircuitBreaker.decorateSupplier(circuitBreaker,
Retry.decorateSupplier(retry, () -> paymentClient.charge(order)));
try {
decoratedSupplier.get();
} catch (Exception e) {
// Обработка ситуации, когда платежный сервис недоступен
// Например, можно сохранить заказ в статусе "ожидает оплаты"
}
}
}Вывод:
Комбинация таймаутов, повторов и Circuit Breaker является стандартным подходом для создания отказоустойчивых микросервисов, способных деградировать при частичных отказах.