Какие способы предотвращения ошибок при вызове одного сервиса из другого существуют, кроме circuit breaker
Что проверяют
Понимаете ли вы, что circuit breaker лишь один элемент защиты, и умеете ли собрать остальные в Java-стеке. Следом обычно спрашивают, в каком порядке комбинировать retry и circuit breaker и почему повтор опасен без идемпотентности.
Как отвечать
- таймауты: connect и read на каждом исходящем клиенте. У
RestTemplateсSimpleClientHttpRequestFactoryони по умолчанию бесконечные, и один зависший сервис съедает все потоки Tomcat. Для асинхронных вызовов естьTimeLimiterв Resilience4j; - retry:
Retryиз Resilience4j или Spring Retry. Экспоненциальная задержка с jitter, лимит попыток, повтор только временных ошибок (таймаут, 503) и только идемпотентных операций; - идемпотентность: ключ идемпотентности в заголовке для
POST, чтобы повтор не создал второй платёж; - bulkhead:
Bulkheadна семафоре илиThreadPoolBulkheadвыделяют каждой зависимости свою квоту, медленный сервис не блокирует остальные; - rate limiter:
RateLimiterограничивает исходящую частоту, чтобы не положить соседа всплеском; - fallback: кэшированный ответ, значение по умолчанию или урезанная функция вместо ошибки;
- асинхронность: вместо синхронного вызова сообщение в Kafka или RabbitMQ, паттерн transactional outbox и DLQ для необработанных сообщений;
- service mesh: Istio или Linkerd выносят таймауты, ретраи и отсечение нездоровых экземпляров в sidecar.
Добавьте про порядок: по умолчанию аннотации Resilience4j вкладываются так, что Retry оказывается снаружи CircuitBreaker. Поэтому CallNotPermittedException от открытого предохранителя стоит исключить из повторов, иначе retry будет впустую долбить закрытую дверь.
Где спотыкаются
Ставят retry без задержки и лимита. Нагрузка множится: в цепочке из четырёх сервисов, где каждый делает по три попытки, одна операция превращается в 27 вызовов последнего.
Повторяют неидемпотентные операции. Таймаут не значит, что запрос не выполнился: списание могло пройти, а ответ потеряться.
Не согласуют таймауты по цепочке. Если внешний клиент ждёт 2 секунды, а внутри три попытки по 3 секунды, сервис продолжает работу, результат которой уже никому не нужен.