Питання 15 · Розділ 17

Як організувати комунікацію між мікросервісами

Мікросервіси спілкуються двома основними способами:

Мовні версії: English Russian Ukrainian

🟢 Junior Level

Мікросервіси спілкуються двома основними способами:

1. Синхронна (HTTP/gRPC):

Сервіс A → HTTP запит → Сервіс B → HTTP відповідь → Сервіс A

2. Асинхронна (Kafka/RabbitMQ):

Сервіс A → повідомлення в Queue → Сервіс B забере коли буде готовий

🟡 Middle Level

Синхронна комунікація

REST:

@RestController
public class OrderController {
    private final UserServiceClient userService;

    @GetMapping("/orders/{id}")
    public Order getOrder(@PathVariable Long id) {
        Order order = orderRepository.findById(id);
        User user = userService.getUser(order.userId());
        return new Order(order, user);
    }
}

gRPC:

service UserService {
    rpc GetUser (UserRequest) returns (UserResponse);
}

Асинхронна комунікація

Kafka:

@KafkaListener(topics = "user-events")
public void onUserEvent(UserEvent event) {
    if (event.type() == USER_CREATED) {
        userRepository.save(event.toUser());
    }
}

Типові помилки

  1. Cascading failures:
    Service A → B → C → D
    D впав → C впав → B впав → A впав
    Рішення: Circuit Breaker, Timeout
    

🔴 Senior Level

Архітектурні Trade-offs

Коли НЕ використовувати синхронну комунікацію

  • Довгі ланцюжки викликів (A→B→C→D) — cascade failure risk
  • Фонові завдання (надсилання email, генерація звіту)
  • Високе навантаження — асинхронна краще буферизує піки
Синхронна Асинхронна
Простіше: один HTTP-виклик → відповідь, немає overhead на broker і серіалізацію. Відмовостійкіше
Швидше для простих випадків: немає overhead на broker і серіалізацію. Краще для масштабування
Coupling у часі Decoupled
Cascading failures Eventual consistency

Production Experience

API Composition:

// thenCombine — об'єднує два futures, дочекавшись обох.
// join() — блокує до результату (як get(), але без checked exception).
// Якщо один future впаде — весь pipeline CompletableFuture завершиться з помилкою.
@GetMapping("/dashboard/{userId}")
public CompletableFuture<Dashboard> getDashboard(@PathVariable Long userId) {
    CompletableFuture<User> user = userService.getUserAsync(userId);
    CompletableFuture<List<Order>> orders = orderService.getOrdersAsync(userId);
    CompletableFuture<List<Notification>> notifications =
        notificationService.getNotificationsAsync(userId);

    return user.thenCombine(orders, (u, o) ->
        new Dashboard(u, o, notifications.join()));
}

Best Practices

✅ Асинхронна для подій
✅ Синхронна для запитів даних
✅ Circuit Breaker для синхронних викликів
✅ Idempotency для асинхронних повідомлень

❌ Довгі ланцюжки викликів
❌ Без timeout і retry
❌ Без обробки помилок

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Два способи: синхронна (HTTP/gRPC) та асинхронна (Kafka/RabbitMQ)
  • Синхронна: простіша, миттєва відповідь, але cascade failure risk
  • Асинхронна: відмовостійкіша, масштабованість, але eventual consistency
  • API composition: об’єднання результатів з кількох сервісів (CompletableFuture.thenCombine)
  • Circuit Breaker для синхронних викликів обов’язковий
  • Idempotency для асинхронних повідомлень обов’язкова
  • НЕ використовуйте синхронну для довгих ланцюжків (A→B→C→D), фонових завдань, високого навантаження

Часті уточнюючі питання:

  • REST vs gRPC? REST простіший, gRPC швидший (protobuf), строгіший контракт.
  • Kafka vs RabbitMQ? Kafka — persistent log, replay, higher throughput. RabbitMQ — flexible routing, easier setup.
  • Як уникнути cascade failure? Circuit Breaker, Timeout, Retry — для синхронних; async queue — для фонових.
  • Що таке API composition? Запит до кількох сервісів паралельно, об’єднання результатів (thenCombine).

Червоні прапорці (НЕ говорити):

  • “Синхронна завжди краща, простіша” — ні, cascade failure risk
  • “Асинхронна для всього” — ні, складніше дебажити, eventual consistency
  • “Ланцюжок A→B→C→D→E — нормальна практика” — ні, cascade failure гарантований
  • “Idempotency не потрібна для Kafka” — потрібна, duplicate delivery можливий

Пов’язані теми:

  • [[16. У чому різниця між синхронною та асинхронною комунікацією]]
  • [[5. Що таке патерн Circuit Breaker]]
  • [[19. Що таке патерн Retry і як його правильно використовувати]]
  • [[9. Що таке API Gateway і які завдання він вирішує]]
  • [[2. У чому різниця між хореографією та оркестрацією в Saga]]