Рубрики
Без рубрики

Весенний облачный поток с RabbitMQ: Микросервисы, управляемые сообщениями

Автор оригинала: Dhananjay Singh.

Обзор

В этой статье мы познакомим вас с Spring Cloud Stream , который представляет собой платформу для создания приложений микросервисов , управляемых сообщениями, которые подключены к общим брокерам обмена сообщениями, таким как RabbitMQ , Apache Kafka и т. Д.

Spring Cloud Stream построен поверх существующих фреймворков Spring, таких как Обмен сообщениями Spring и Интеграция Spring . Хотя эти фреймворки проверены в боях и работают очень хорошо, реализация тесно связана с используемым брокером сообщений. Кроме того, иногда бывает трудно масштабировать для определенных случаев использования.

Идея Spring Cloud Stream – это очень типичная концепция загрузки Spring – поговорите с ней абстрактно, и пусть Spring выяснит детали реализации во время выполнения на основе конфигурации и управления зависимостями. Это означает, что вы можете изменить брокер сообщений с подчеркиванием, просто изменив зависимости и файл конфигурации. Различные брокеры, которые в настоящее время поддерживаются, можно найти здесь .

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

Обмен сообщениями в микросервисах

В архитектуре микросервиса у нас есть много небольших приложений, которые взаимодействуют друг с другом для выполнения запроса – одним из главных преимуществ их является улучшенная масштабируемость. Довольно часто один запрос передается от нескольких нижестоящих микросервисов для завершения. Например, предположим, что у нас есть Service-A , который внутренне вызывает Service-B и Service-C для выполнения запроса:

Да, были бы и другие компоненты , такие как Spring Cloud Eureka , Spring Cloud Zuul и многие другие, но мы пытаемся сосредоточиться на конкретной проблеме с этим типом архитектуры.

Предположим, по какой-то причине Service-B требуется немного больше времени для ответа. Возможно, он выполняет операцию ввода-вывода или длительную транзакцию БД или дополнительно вызывает различные службы, которые требуют, чтобы она была медленной таким образом, чтобы ее нельзя было сделать более эффективной.

Теперь мы можем запустить больше экземпляров Service-B , чтобы справиться с этим , и это нормально, но Service-A , который на самом деле быстрый, должен дождаться ответа от Service-B , чтобы продолжить. Это приводит к тому, что Service-A не может получать больше запросов, что означает, что нам также приходится запускать несколько экземпляров Service-A .

Другой подход к решению подобной ситуации заключается в использовании архитектуры микросервисов, управляемой событиями. В основном это означает, что вместо того, чтобы Service-A совершать вызовы Service-B или Service-C напрямую через HTTP, он публикует запрос или событие брокеру сообщений/|. Service-B и Service-C будут подписчиками на это событие в брокере сообщений.

Это имеет много преимуществ по сравнению с традиционной архитектурой микросервисов, которая опирается на HTTP-вызовы:

  • Повышает масштабируемость и надежность – Теперь мы знаем, какие сервисы являются истинными узкими местами в нашем общем приложении.
  • Поощряет слабую связьСервис A не нужно знать о Сервис-B и Сервис-C . Все, о чем ему нужно позаботиться, – это подключиться к брокеру сообщений и опубликовать событие. Дальнейшая организация мероприятия зависит от настроек брокера. Таким образом, Service-A может развиваться независимо, что является одной из основных концепций микросервисов.
  • Взаимодействие с устаревшей системой – Довольно часто мы не можем перенести все в более новый технологический стек. Нам все еще приходится работать с устаревшей системой, которая, хотя и медленная, но надежная.

Кролик

Расширенный протокол очереди сообщений (AMQP) – это протокол, который RabbitMQ использует для обмена сообщениями. Хотя RabbitMQ поддерживает некоторые другие протоколы, AMQP наиболее предпочтителен из-за совместимости и большого набора функций, которые он предлагает.

Архитектурный дизайн RabbitMQ

Таким образом, издатель публикует сообщение на что-то под названием Exchange в RabbitMQ. Exchange принимает сообщение и направляет его в одну или несколько очередей . Алгоритмы маршрутизации зависят от типа exchange и ключа маршрутизации/заголовка (передается вместе с сообщением). Эти правила, которые подключают обмен к очереди, называются привязками .

Привязки могут быть 4 типов:

  • Direct : Он напрямую сопоставляет тип обмена с определенной очередью на основе ключа маршрутизации.
  • Разветвление : Он направляет сообщения во все очереди связанного обмена.
  • Тема : Он направляет сообщения в очереди (0, 1 или более) на основе полного или частичного совпадения ключей маршрутизации.
  • Заголовки : Он похож на тип обмена темами, но он маршрутизирует на основе значений заголовков, а не ключей маршрутизации.

Кредиты – Кредиты –

Эта общая публикация и потребление сообщений через обмены и очереди осуществляется по каналу .

Для получения более подробной информации о маршрутах, пожалуйста, посетите эту ссылку .

Настройка RabbitMQ

Установка

Мы можем загрузить и настроить двоичные файлы на основе вашей операционной системы с здесь .

Однако в этой статье мы будем использовать бесплатную облачную установку, предоставляемую cloudamqp.com . Просто зарегистрируйтесь на сервисе и войдите в систему.

На главной панели управления нажмите “Создать новый экземпляр”:

Затем дайте вашему экземпляру имя и перейдите к следующему шагу:

Затем выберите регион:

И последнее, просмотрите информацию о своем экземпляре и нажмите “Создать экземпляр” в правом нижнем углу:

Вот и все. Теперь у вас есть установка RabbitMQ, запущенная в облаке. Для получения более подробной информации о вашем экземпляре перейдите на панель мониторинга и нажмите на вновь созданный экземпляр:

Мы можем видеть хост, с которого мы можем получить доступ к нашему экземпляру Rabbitmq, например, имя пользователя и пароль, необходимые для подключения к нашему проекту:

Мы будем использовать “URL-адрес AMQP” в нашем весеннем приложении для подключения к этому экземпляру, поэтому где-нибудь запишите его.

Вы также можете увидеть консоль менеджера, нажав “RabbitMQManager” в левом верхнем углу. Это приведет к управлению вашим экземпляром RabbitMQ, который выглядит примерно так:

Настройка проекта

Теперь, когда наша настройка готова, давайте создадим наши сервисы:

  • облачный поток-производитель-rabbitmq : Это будет действовать как издатель, который будет отправлять сообщения в RabbitMQ
  • облачный поток-потребитель-rabbitmq : Это будет потреблять сообщения

Лучший способ начать со скелетного проекта-использовать Spring Initializr . Это будет наш проект производителя, и мы будем использовать конечные точки REST для публикации сообщений.

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Выберите предпочитаемую версию Spring Boot, добавьте зависимости “Веб” и “Облачный поток” и создайте как проект Maven:

Примечание : Обратите внимание на сообщение в скобках в зависимости cloud-stream . В нем говорится, что для этого также требуется зависимость от связующего, такая как RabbitMQ, Кафка и т. Д. работать.

Поскольку мы будем использовать RabbitMQ, добавьте следующую зависимость Maven:


  org.springframework.cloud
  spring-cloud-stream-binder-rabbit

В качестве альтернативы мы также можем объединить их и использовать стартер Spring Cloud Stream RabbitMQ:


  org.springframework.cloud
  spring-cloud-starter-stream-rabbit

Аналогично, создайте потребительский проект, но только с зависимостью spring-cloud-starter-stream-rabbit .

Создание производителя

Как мы уже говорили ранее, общий процесс передачи сообщений от издателя для обмена в очередь выполняется по каналу. Итак, давайте создадим Привязку приветствия интерфейс, содержащий наш Канал сообщений под названием “Канал приветствия”:

interface HelloBinding {

    @Output("greetingChannel")
    MessageChannel greeting();
}

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

Теперь давайте создадим конечную точку REST, которая отправляет сообщения на этот канал:

@RestController
public class ProducerController {

    private MessageChannel greet;

    public ProducerController(HelloBinding binding) {
        greet = binding.greeting();
    }

    @GetMapping("/greet/{name}")
    public void publish(@PathVariable String name) {
        String greeting = "Hello, " + name + "!";
        Message msg = MessageBuilder.withPayload(greeting)
            .build();
        this.greet.send(msg);
    }
}

Выше мы создали Контроллер производителя класс, который имеет атрибут приветствие типа Канал сообщений . Это инициализируется в конструкторе методом, который мы объявили ранее.

Примечание : Мы также могли бы сделать то же самое компактным способом, но мы используем разные имена, чтобы дать вам больше ясности в том, как все взаимосвязано.

Затем у нас есть простое отображение REST, которое принимает имя из переменной Пути и создает Сообщение типа Строка с помощью MessageBuilder . В конце концов, мы использовали метод .send() в канале сообщений для публикации сообщения.

Теперь мы должны рассказать Spring о нашем HelloBinding , что мы сделаем в нашем основном классе , используя @EnableBinding аннотацию:

@EnableBinding(HelloBinding.class)
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

В конце концов, мы должны рассказать Spring, как подключиться к RabbitMQ (через “URL-адрес AMQP”, указанный ранее), и найти способ подключения “канала приветствия” к возможному потребителю.

Оба они определены в application.properties :

spring.rabbitmq.addresses=

spring.cloud.stream.bindings.greetingChannel.destination = greetings

server.port=8080

Создание потребителя

Теперь нам нужно прослушать канал, который мы создали ранее, т. е. “Канал приветствия”. Давайте создадим для него привязку:

public interface HelloBinding {

    String GREETING = "greetingChannel";

    @Input(GREETING)
    SubscribableChannel greeting();
}

Два отличия от привязки производителя должны быть совершенно очевидны. Поскольку мы потребляем сообщение, мы используем Подписной канал и @Ввод аннотацию для подключения к “каналу приветствия”, куда будут передаваться данные.

Теперь давайте создадим метод, в котором мы будем фактически обрабатывать данные:

@EnableBinding(HelloBinding.class)
public class HelloListener {

    @StreamListener(target = HelloBinding.GREETING)
    public void processHelloChannelGreeting(String msg) {
        System.out.println(msg);
    }
}

Здесь мы создали класс HelloListener , в котором есть метод с аннотацией @StreamListener , предназначенный для “канала приветствия”. Этот метод ожидает Строку в качестве аргумента, который мы только что зарегистрировали в консоли. Мы также включили HelloBinding здесь, используя @EnableBinding в верхней части класса.

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

Давайте также посмотрим наш основной класс, который мы не меняли:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

В application.properties нам нужно определить то же самое, что мы сделали для производителя, за исключением того, что это будет выполняться на другом порту:

spring.rabbitmq.addresses=
spring.cloud.stream.bindings.greetingChannel.destination=greetings
server.port=9090

Проверяю Все это

Давайте начнем как с производителя, так и с обслуживания потребителей. Во-первых, давайте создадим сообщение, нажав на вашу конечную точку http://localhost:8080/greet/john .

В журналах пользователей вы можете увидеть сообщение:

Давайте запустим другой экземпляр службы обслуживания потребителей (на другом порту), используя следующую команду:

$ mvn spring-boot:run -Dserver.port=9091

Теперь, когда мы нажимаем конечную точку REST производителя для публикации, мы видим, что оба потребителя получили сообщение:

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

spring.cloud.stream.bindings.greetingChannel.group = greetings-group

Теперь снова запустите 2 экземпляра потребителя на разных портах и проверьте еще раз, опубликовав через производителя:

Все это также можно увидеть визуально в консоли RabbitMQ manager:

Вывод

В этой статье мы объяснили основную концепцию обмена сообщениями, ее роль в микросервисах и то, как ее реализовать с помощью Spring Cloud Stream. Мы использовали RabbitMQ в качестве нашего брокера сообщений, но мы можем использовать других популярных брокеров, таких как Кафка, просто изменив конфигурацию и зависимости.

Как всегда, код для примеров, используемых в этой статье, можно найти на GitHub