JavaRush /Курсы /Модуль 5. Spring /Лекция 168: Подходы к коммуникации между микросервисами: ...

Лекция 168: Подходы к коммуникации между микросервисами: синхронная (REST) и асинхронная (сообщения)

Модуль 5. Spring
17 уровень , 7 лекция
Открыта

Пришло время обсудить то, как эти автономные учёные-микросервисы всё-таки "общаются" друг с другом. И тут, как в жизни, есть два популярных способа: говорить напрямую (синхронно) или отправлять письма/сообщения (асинхронно).

Представьте обычный рабочий процесс в офисе. Когда вам срочно нужна информация от коллеги, вы подходите к нему напрямую или звоните (синхронная коммуникация). Когда задача не горит, вы отправляете email и спокойно занимаетесь другими делами, пока ждете ответ (асинхронная коммуникация). Выбор способа общения зависит от срочности и важности вопроса.

Точно так же и микросервисы могут общаться разными способами в зависимости от их задач. Например:

  • Если микросервису A нужен немедленный ответ от микросервиса B, он обращается к нему напрямую через REST API.
  • Если микросервису A не важна срочность ответа, он отправит сообщение через брокера (например, Kafka).

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

Синхронная коммуникация через REST API

Синхронная коммуникация означает, что сервис делает запрос и ждёт ответа от другого сервиса. Это похоже на телефонный звонок: вы звоните другу и ждёте, пока он ответит. Если он не отвечает, звоните снова или бросаете трубку.

В мире микросервисов наиболее популярным способом синхронной коммуникации является REST API.

Пример синхронного взаимодействия с REST

Допустим, вы разрабатываете систему заказа еды. У вас есть два микросервиса:

  1. OrderService — отвечает за обработку заказов.
  2. PaymentService — отвечает за обработку платежей.

Сценарий: при оформлении клиентом заказа OrderService должен вызвать PaymentService, чтобы проверить, достаточно ли средств для оплаты. Вот как это может выглядеть:


// OrderService: Вызов REST API PaymentService (синхронный запрос)
@RestController
@RequestMapping("/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
        // Логика создания заказа

        // Отправляем запрос в PaymentService
        RestTemplate restTemplate = new RestTemplate();
        String paymentUrl = "http://localhost:8081/payment/validate";
        PaymentResponse paymentResponse = restTemplate.postForObject(paymentUrl, orderRequest, PaymentResponse.class);

        if (paymentResponse.isPaymentValid()) {
            return ResponseEntity.ok("Order created successfully.");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Payment failed.");
        }
    }
}

Преимущества синхронной коммуникации

  • Простая реализация: REST API — это стандарт, который многие разработчики уже понимают, а инструменты (например, Spring RestTemplate и WebClient) существенно упрощают работу.
  • Прямой доступ: сервис вызывает другой сервис напрямую, получает ответ сразу.
  • Привычность: REST API широко применяется и понятен как разработчикам, так и менеджерам.

Ограничения синхронной коммуникации

  • Временная зависимость: если PaymentService недоступен, то OrderService также "зависает", что может нарушить работу всей системы.
  • Проблемы с масштабированием: если нагрузка на OrderService увеличится, PaymentService также должен справляться с большим количеством запросов.
  • Повышенная задержка: каждый вызов REST — это время ожидания, что может замедлить общую производительность.

Когда использовать синхронную коммуникацию?

  • Когда необходим немедленный ответ.
  • Когда зависимость между сервисами тесная (например, проверка платёжных данных).
  • Когда сбои в одном сервисе критически важны для другого.

Асинхронная коммуникация с использованием сообщений

Асинхронность подразумевает, что один сервис отправляет сообщение другому через брокера (например, Kafka, RabbitMQ или ActiveMQ) и не ждёт немедленного ответа. Это больше похоже на отправку электронной почты: вы написали сообщение и продолжили заниматься своими делами, а получатель ответит, когда сможет.

Основные концепции асинхронной коммуникации

  • Брокеры сообщений (Message Brokers): обычно используется посредник, например, Kafka, который хранит и доставляет сообщения.
  • Продюсер и Консьюмер: сервис-отправитель называется продюсером (producer), а сервис-получатель — консьюмером (consumer).
  • Топики: сообщения отправляются в "топики" (topics), которые действуют как почтовые ящики.

Пример асинхронного взаимодействия через Kafka

Продолжим пример с OrderService и PaymentService. Допустим, мы хотим отправить заказ на оплату асинхронно.

Публикуем сообщение (Продюсер):


// OrderService: Отправка сообщения в Kafka
@RestController
@RequestMapping("/orders")
public class OrderController {

    private final KafkaTemplate<String, OrderRequest> kafkaTemplate;

    public OrderController(KafkaTemplate<String, OrderRequest> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    @PostMapping
    public ResponseEntity<String> createOrder(@RequestBody OrderRequest orderRequest) {
        kafkaTemplate.send("payment-topic", orderRequest); // Отправляем сообщение
        return ResponseEntity.ok("Order created successfully. Payment will be processed.");
    }
}

Обрабатываем сообщение (Консьюмер):


// PaymentService: Получение сообщения из Kafka
@Component
public class PaymentConsumer {

    @KafkaListener(topics = "payment-topic", groupId = "payment-group")
    public void handlePayment(OrderRequest orderRequest) {
        // Логика обработки платежа
        System.out.println("Processing payment for order: " + orderRequest.getOrderId());
    }
}

Преимущества асинхронной коммуникации

  • Снижение зависимости: сервисы работают независимо друг от друга. Даже если PaymentService отключён, OrderService продолжит работать.
  • Повышенная масштабируемость: брокеры сообщений, такие как Kafka, могут обрабатывать огромные объёмы данных.
  • Гибкость взаимодействия: несколько консьюмеров могут подписаться на один топик, что удобно для сложных систем.

Ограничения асинхронной коммуникации

  • Сложность реализации: нужна настройка брокера сообщений и обработка ошибок (например, недоставленных сообщений).
  • Отсутствие немедленного ответа: если успешность операции критична, это может быть проблемой.
  • Гарантии доставки: не все брокеры сообщений поддерживают строгую гарантию доставки.

Когда использовать асинхронную коммуникацию?

  • Когда задача не требует немедленного завершения (например, отправка уведомлений).
  • Когда нужно разъединить сервисы и уменьшить их взаимозависимость.
  • Когда нужно эффективно обрабатывать большой объем данных.

Выбор между синхронной и асинхронной коммуникацией

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

Критерий Синхронная (REST) Асинхронная (Сообщения)
Немедленность ответа Требуется Не требуется
Зависимость между сервисами Высокая Низкая
Объем данных Небольшой Большой
Масштабируемость Ограниченная Высокая
Сложность реализации Низкая Высокая

Типичные ошибки при использовании подходов

  • Использование REST для задач, которые не требуют немедленного ответа, ведёт к увеличению задержек и зависимостей.
  • Пренебрежение обработкой ошибок в асинхронной коммуникации может привести к потере сообщений.
  • Неправильное проектирование топиков Kafka (например, слишком много продюсеров и консьюмеров на одном топике) создаёт хаос.

Чтобы избежать этих проблем, тщательно анализируйте требования системы и выбирайте подход, который лучше всего соответствует вашим целям.


На этом этапе мы уже разобрались, как микросервисы могут взаимодействовать между собой с помощью синхронного REST и асинхронных сообщений. В следующей лекции мы начнём углубляться в декомпозицию приложений для микросервисной архитектуры. Увидимся в коде! 😉

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ