Вопрос 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]]