Sobes.tech
Назад к вопросам
Middle+
125
questionbank

Как бы вы организовали взаимодействие между несколькими сервисами?

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Нужно показать, что взаимодействие сервисов строится не только на выборе REST или gRPC, но и на учёте синхронности, отказоустойчивости и наблюдаемости. Обычно ждут архитектурный ответ: где уместны HTTP-вызовы, где лучше асинхронные сообщения, как сервисы находят друг друга и как защищается внешний вход. Важно упомянуть баланс между простотой интеграции и надёжностью системы.

Определение:

Взаимодействие между несколькими сервисами обычно организуют как комбинацию синхронных и асинхронных каналов связи. Для запросов с немедленным ответом используют REST или gRPC, для событий и длительных процессов — message queue или event bus. Снаружи систему часто прикрывают API Gateway, а внутри — service discovery, таймауты, ретраи и схемы версионирования контрактов.

Пример использования:

Допустим, есть сервисы Order, Payment и Inventory.
Пользователь создаёт заказ через API Gateway, который маршрутизирует запрос в Order Service. Order Service синхронно проверяет доступность товара через Inventory Service, а затем публикует событие OrderCreated в очередь. Payment Service читает событие, проводит оплату и публикует PaymentCompleted, после чего Order Service переводит заказ в финальный статус.

// Упрощённый пример: синхронный вызов + публикация события

@RestController
@RequestMapping("/orders")
class OrderController {
    private final InventoryClient inventoryClient;
    private final EventPublisher eventPublisher;

    OrderController(InventoryClient inventoryClient, EventPublisher eventPublisher) {
        this.inventoryClient = inventoryClient;
        this.eventPublisher = eventPublisher;
    }

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody CreateOrderRequest request) {
        boolean available = inventoryClient.checkAvailability(request.productId(), request.quantity());
        if (!available) {
            return ResponseEntity.badRequest().body("Not enough stock");
        }

        // сохраняем заказ в БД (опущено)
        eventPublisher.publish("OrderCreated", request);

        return ResponseEntity.accepted().body("Order accepted");
    }
}

interface InventoryClient {
    boolean checkAvailability(String productId, int quantity);
}

interface EventPublisher {
    void publish(String topic, Object payload);
}

record CreateOrderRequest(String productId, int quantity) {}

Пояснение кода:

OrderController принимает запрос на создание заказа. Сначала он синхронно обращается к InventoryClient, чтобы быстро проверить остатки товара. Если товара нет, запрос завершается с ошибкой. Если всё в порядке, заказ принимается и отправляется событие OrderCreated через EventPublisher, чтобы другие сервисы могли обработать его асинхронно.

Шаги работы примера:

  1. Клиент отправляет запрос в POST /orders.
  2. Сервис заказа синхронно проверяет остатки в сервисе склада.
  3. Если проверка успешна, заказ сохраняется.
  4. В очередь/шину публикуется событие о создании заказа.
  5. Сервис оплаты или другие подписчики обрабатывают событие независимо и не блокируют создание заказа.

Ключевые моменты:

  • Для быстрых запросов и простых CRUD-сценариев обычно подходит REST.
  • Для низкой задержки и строгого контракта между сервисами часто выбирают gRPC.
  • Для слабой связности и устойчивости к сбоям лучше использовать асинхронные сообщения.
  • API Gateway удобен как единая точка входа для внешних клиентов.
  • Service Discovery нужен, если адреса сервисов динамические и меняются при масштабировании.
  • Обязательно нужны таймауты, ретраи, circuit breaker и идемпотентность, иначе каскадные сбои быстро «положат» систему.