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

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

Ответ

Выбор типа взаимодействия зависит от требований к связности, производительности, масштабируемости и отказоустойчивости системы.

Тип взаимодействия Когда использовать Пример технологии/паттерна
Синхронный вызов (RPC/REST) Для простых, быстрых операций, где нужен немедленный ответ. Подходит для tightly-coupled сервисов в одном trust-домене. REST API, gRPC, SOAP, прямой вызов метода.
Асинхронное сообщение (Message Queue) Для слабосвязанных систем, фоновой обработки, обеспечения надежности и балансировки нагрузки. Apache Kafka, RabbitMQ, AWS SQS, JMS.
Событийное (Event-Driven) Когда компоненты должны реагировать на изменения состояния других компонентов без прямого вызова. Паттерны Event Sourcing, CQRS, использование брокеров (Kafka).
Широковещательное / Многоадресное Для передачи данных множеству получателей одновременно (например, обновления конфигурации). UDP multicast, Redis Pub/Sub.

Практические примеры:

1. Синхронный REST-запрос (Spring Boot):

@RestController
public class UserController {
    @GetMapping("/users/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        // Немедленный ответ, поток блокируется
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
}

2. Асинхронное взаимодействие через Kafka:

// Producer отправляет сообщение и не ждет обработки
@Autowired private KafkaTemplate<String, String> kafkaTemplate;
public void sendOrderEvent(Order order) {
    kafkaTemplate.send("order-topic", order.toJson());
}
// Consumer обрабатывает сообщение когда сможет
@KafkaListener(topics = "order-topic")
public void processOrder(String message) {
    // Асинхронная обработка заказа
}

Критерии выбора:

  • Задержка (Latency): Синхронные вызовы дают минимальную задержку, если сервис быстрый.
  • Связность (Coupling): Асинхронные сообщения уменьшают связность.
  • Надежность (Reliability): Очереди сообщений обеспечивают persistence и retry.
  • Масштабируемость (Scalability): Event-driven архитектура и очереди упрощают горизонтальное масштабирование.