Статьи

Управляемая событиями оркестровка: эффективная интеграция микросервисов с использованием BPMN и AMQP

В современном мире ИТ архитектура микросервисов становится привлекательной. По сравнению с традиционным монолитным приложением, микросервисы предоставляют различные преимущества, такие как идеальное соответствие гибкой методологии, нативная и облачная разработка, большее разделение задач, более высокая масштабируемость и гибкость, а также более быстрое выполнение. Однако деловые организации столкнутся со следующими проблемами при переносе монолитного корпоративного приложения в микросервисы:

  • Увеличение сложности в интеграции распределенных услуг
  • Трудности в управлении распределенными транзакциями, охватывающими более одного сервиса
  • Информационные барьеры, в которых отсутствует сквозное управление бизнес-потоками через сервисы

В этой статье мы рассмотрим пример бизнес-процесса «отправить корзину» и обсудим два классических шаблона интеграции микросервисов: хореография сервисов и оркестровка. Оценивая плюсы и минусы каждого подхода, мы сделаем еще один шаг, чтобы рассмотреть предлагаемое решение: управляемую событиями оркестровку. Мы исследуем методы проектирования для создания слабосвязанного и многократно используемого приложения с использованием Spring Boot, механизма бизнес-процессов Camunda и системы обозначений (BPMN) и RabbitMQ, брокера сообщений на основе Advanced Message Queuing Protocol (AMQP). Полностью рабочий пример проекта можно найти на GitHub .

Пример использования «Отправить корзину»

Давайте рассмотрим типичный бизнес-процесс «отправить корзину», который состоит из пяти основных этапов:

  1. Подтвердите адрес доставки
  2. Резервный платеж
  3. Распределить инвентарь
  4. Разместить заказ
  5. Уведомить клиента

Бизнес-процесс выполнит пять шагов в последовательности. В случае возникновения исключительной ситуации во время рабочего процесса необходимо выполнить откат для поддержки ACID транзакции (атомарной, согласованной, изолированной и надежной).

Как этот бизнес-процесс «отправить корзину» может быть реализован как группа взаимодействий между микросервисами?

Вариант решения 1: Событийная сервисная хореография

Одним из возможных решений является следование принципу микросервиса «Умная конечная точка и тупой канал» и создание децентрализованной хореографии услуг.

Как показано на рисунке 1 ниже, сервисы подключаются к шине сообщений и подписываются на интересующие их события. Как только происходит событие, имеющее значение для сервиса, сервис выполняет соответствующее действие. Процесс «отправки корзины покупок» будет инициирован событием от внешнего пользователя и будет обрабатываться задействованными микросервисами в режиме хореографии. Такой подход обеспечивает высокую когезию и низкую связь.

Рисунок 1. Сервисная хореография с использованием Message Broker.

Однако этот подход имеет следующие недостатки:

  • Сложно поддерживать: благодаря децентрализованному решению бизнес-поток распространяется на несколько сервисов. Любое изменение бизнеса в потоке процессов приведет к изменениям в нескольких сервисах.
  • Сложно управлять: состояние выполнения экземпляра процесса хранится отдельно.
  • Сложно откатить: бизнес-процесс хореографируется несколькими службами, которые оставляют ACID транзакции чрезвычайно трудным.

Вариант решения 2: Централизованная сервисная оркестровка

Другое решение заключается во внедрении централизованной службы оркестровки с использованием рабочего процесса BPMN и интеграции REST. Как показано на рисунке 2, «Микросервис корзины покупок» реализован как централизованное управление процессом корзины покупок.

Рисунок 2. Сервисная оркестровка с использованием BPMN и REST.

Используя механизм процесса BPMN и интеграцию REST, решаются проблемы варианта 1:  

  • Простота обслуживания: бизнес-процесс моделируется как графический BPMN-процесс в микросервисе централизованной оркестровки. Стандартная модель и нотация бизнес-процессов (BPMN) предоставляет предприятиям возможность понимать свои внутренние бизнес-процедуры в графической нотации. Кроме того, организации могут лучше общаться и сообщать об этих процедурах стандартным образом. Любые дальнейшие изменения в потоке процесса будут смягчены путем внедрения диаграмм рабочего процесса.
  • Простота управления: BPMN Process Engine отслеживает все экземпляры процессов, их состояние, данные аудита и статистики.
  • Легкий откат: ACID транзакции может быть гарантирован потоком компенсации как встроенная функция BPMN.

К сожалению, этот подход также имеет недостатки:

  • Тесная связь: шаблон оркестровки должен создавать и поддерживать двухточечное соединение между сервисами. Точка-точка означает, что один сервис вызывает API другого сервиса, что приводит к созданию сети путей связи между всеми сервисами. Интеграция, изменение или удаление сервисов из репозитория сервисов будет сложной задачей, так как вы должны знать каждое соединение между сервисами.
  • Сложность построения сервисных адаптеров. Сервису Orchestration необходимо разработать адаптеры для одноранговых сервисов, которые должны поддерживать все детали взаимодействия сервисов, такие как местоположение сервисов, интерфейсы сервисов и трансляция модели данных. Всякий раз, когда меняется одноранговая служба, это влияет на адаптер.

Какое решение лучше?

Предлагаемое решение: управляемая событиями сервисная оркестровка

Предлагается решение событийно-ориентированной и централизованной оркестровки. Как показано на рисунке 3, сервис корзины покупок реализован как сервис оркестрации с использованием рабочего процесса BPMN, но сервисные адаптеры исключаются с помощью стандартного готового адаптера AMQP. Шина событий AMQP разработана в качестве посредника сообщений для отделения сервисов.

Рисунок 3. Управляемая событиями оркестровка с использованием BPMN и AMQP.

Как показано на рисунке 3, этот подход состоит из следующих архитектурных компонентов:

Централизованная служба оркестровки с использованием BPMN Workflow

Централизованная служба оркестровки состоит из следующих подкомпонентов:

Приложение Spring Boot с поддержкой BPMN

@SpringBootApplication 
@EnableProcessApplication
public class ShoppingCartServiceApplication {
    public static void main(String... args) {
        SpringApplication.run(ShoppingCartServiceApplication.class, args);
    }
}

BPMN рабочие процессы

Основной рабочий процесс «отправить корзину» показан ниже:

Рисунок 4. Пример рабочего процесса BPMN для «отправить корзину».

Поток компенсации за откат транзакции для обработки исключений:

Рисунок 5. Пример потока компенсации BPMN для исключений.

BPMN Workflow

Действия рабочего процесса спроектированы как компоненты Spring, которые реализуют интерфейс Camunda JavaDelegate. Благодаря использованию готового адаптера AMQP и модели общих событий бизнес-поток и его деятельность можно упростить, чтобы сосредоточиться на своей бизнес-логике. Пример активности резервного платежа при вызове платежного сервиса через AMQP «RPC» показан ниже:

@Component
public class ReservePaymentActivity implements JavaDelegate {
    . . . 
    public static final String SERVICE_ACTION = "reserve";

    @Autowired
    AmqpRpcClient amqpRpcClient;

    @Override
    public void execute(DelegateExecution execution) throws Exception {
        BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
        ServiceResponse response = amqpRpcClient.invokeService(
        ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_PAYMENT, SERVICE_ACTION));
        ProcessUtil.processResponse(execution, response);
        execution.setVariable(ProcessConstants.VAR_PAYMENT_RESERVED, true);
    }
}

AMQP Event Bus

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

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

Рисунок 6. Управляемая событиями архитектура с использованием AMQP.

Для разработки слабосвязанного и многократно используемого решения предлагаются следующие методы проектирования:

Каноническая модель сообщения

Модель общего канонического сообщения предназначена для связи через микросервисы. В примере проекта модели сообщений разрабатываются как унифицированные общие модели с использованием схемы JSON.

Ниже приведен пример модели «Запрос на обслуживание», который опирается на общую модель данных как «Бизнес-объект». Бизнес-объект может быть смоделирован для любых реальных объектов, таких как корзина покупок, продукт, платежная позиция или адрес и т. Д.

В реальном проекте рекомендуются стандартные доменные модели, такие как TM Forum SID для телекоммуникационной отрасли.

{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "id": "ServiceRequest.json",
  "title": "Service Request",
  "type": "object",
  "javaType": "com.microservice.orchestration.demo.entity.ServiceRequest",
  "additionalProperties": false,
  "properties": {
    "id": {
      "type": "string"
    },
    "serviceName": {
      "type": "string"
    },
    "serviceAction": {
      "type": "string"
    },
    "createdDate": {
      "type": "string"
    },
    "createdBy": {
      "type": "string"
    },
    "items": {
      "type": "array",
      "items": {
        "$ref": "BusinessEntity.json#"
      }
    }
  }
}

Готовый адаптер AMQP

Как показано на рисунке 6, универсальный адаптер AMQP разработан как компонент многократного использования для микросервисов. Адаптер поддерживает два варианта взаимодействия сервисов: Pub / Sub и RPC.

Адаптер скрывает детали конфигураций AMQP и предоставляет готовые компоненты, как показано ниже:

  • Компоненты для производителя событий

    • AmqpPublisher : пружинный компонент публикует событие в шине событий AMQP.
    • AmqpRpcClient : пружинный компонент синхронно вызывает API к одноранговой службе, отправляя запрос на шину AMQP и получая ответ.
  • Компоненты для потребителя событий

    • AmqpSubscriber: a spring bean consumes the event from the AMQP event bus and executes the business logic asynchronously.
    • AmqpRpcServer: a spring bean executes the business logic for a request from the client and responds back to client synchronously.

Configuration-Based AMQP Event Routing

The event producer service will specify the AMQP “exchanges” that are used to invoke a service or publish a message. By passing the configurations from microservice instance to the pre-built AMQP adapter, the event producer can be instantiated without any coding effort.

Below is the sample configuration for the shopping cart service as an event producer: the application.yaml configuring the exchanges for Pub/Sub and RPC.

spring:
  rabbitmq:
exchange:
  rpc: shoppingcart.rpc  
  pub: shoppingcart.pub

The event consumer will configure the message routings in the pattern of “Exchange”->”Routing Key”->”Event Queue”.This pattern can be better understood and maintained.  

Below is the sample configuration for the Location Service as an event consumer: the event routing paths are configured in a simple and intuitive way. The «serviceRoutings» defines the event paths for the synchronous RPC event flows, and the «eventRoutings» defines the event flows for the asynchronous Pub/Sub.

spring:
  rabbitmq:
    serviceRoutings:
    - shoppingcart.rpc->LocationService.*->LocationServiceQueue
    - customer.rpc->LocationService.*->LocationServiceQueue
    eventRoutings:
    - shoppingcart.pub->LocationService.*->LocationEventQueue
    - customer.pub->LocationService.*->LocationEventQueue

Service Providers With Injectable Event Handler

In the event-driven architecture, the microservices that are providing the business functions are registered as AMQP event consumers.

The event consumer services will serve the business function by implementing the “EventHandler” interface. This event handler service will be injected into the pre-built AMQP consumer. By doing so, the common AMQP adapter is decoupled from the business details of the actual event consumer service.

A sample event handler of the Order Service looks like as below:

@Service
public class OrderServiceEventHandler implements EventHandler {
. . . 

    @Override
    public ServiceResponse processRequest(ServiceRequest request) {
        //Dispatch service request to worker
        . . . 
        ServiceResponse response = OrderServiceDelegate.invokeService(request);
        return response;
    }

    @Override
    public void processEvent(ServiceRequest request) {
        //Dispatch service event to handler
        OrderServiceDelegate.handleEvent(request);
    }
}

Conclusion

This article discusses the widely-used approaches of microservices integration: service choreography and orchestration. By analyzing the pros and cons of each way, a better solution of event-driven orchestration is proposed.

A sample project can be found in GitHub using Spring Boot, the Camunda BPMN process engine, and the Rabbit MQ. Looking at the sample code, we have discussed the design practices in building the event-driven solution as loosely coupled, highly reusable, more manageable and maintainable. Moreover, the centralized orchestration using BPMN allows us to manage the complex business flows and the distributed transactions in an intuitive way.