Когда для взаимодействия микросервисов предпочтителен синхронный вызов (REST/gRPC)?

«Когда для взаимодействия микросервисов предпочтителен синхронный вызов (REST/gRPC)?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Прямые синхронные вызовы (REST API, gRPC) уместны, когда необходим немедленный, транзакционный ответ в рамках одного запроса от клиента.

Ключевые сценарии применения:

  • Синхронные цепочки действий (SAGA Orchestration): Когда следующий шаг зависит от результата предыдущего.
    • Пример: Проверить запас товара → Заблокировать товар → Создать заказ.
  • Запросы данных в реальном времени: Получение текущего баланса пользователя, проверка авторизации (API Gateway → Auth Service).
  • Простая CRUD-логика: В небольших системах или внутри защищенного периметра, где сложность асинхронности не оправдана.
  • Ситуации, где важен немедленный успех/ошибка: Операция оплаты, где клиент должен сразу узнать результат.

Пример синхронного REST-вызова (Spring Boot):

@Service
public class PaymentService {
    @Autowired
    private RestTemplate restTemplate;

    public PaymentResult processPayment(PaymentRequest request) {
        // 1. СИНХРОННЫЙ вызов для проверки баланса
        ResponseEntity<Boolean> balanceCheck = restTemplate.postForEntity(
            "http://account-service/api/v1/balance/check",
            request,
            Boolean.class
        );
        if (!balanceCheck.getBody()) {
            throw new InsufficientFundsException(); // Немедленная ошибка клиенту
        }

        // 2. СИНХРОННЫЙ вызов для списания средств
        restTemplate.postForEntity(
            "http://account-service/api/v1/balance/debit",
            request,
            Void.class
        );

        // 3. Локальная операция - создание записи о платеже
        return createPaymentRecord(request);
    }
}

⚠️ Риски прямых вызовов:

  • Жесткая связь (Tight Coupling): Сервис-потребитель должен знать эндпоинт и формат ответа сервиса-провайдера.
  • Каскадные отказы: Падение одного сервиса может «повалить» всю цепочку вызовов. Для смягчения необходимы Circuit Breaker (Hystrix, Resilience4j) и повторные попытки (Retry).
  • Снижение производительности: Общее время ответа равно сумме задержек всех вызванных сервисов.

Итог: Используйте синхронную коммуникацию для прямых, транзакционных запросов, но обязательно применяйте паттерны устойчивости к отказам.