В течение длительного времени мы выступали за архитектуру, в которой BPM-движок Camunda встроен в ваше Java-приложение, предпочтительно через Camunda Spring Boot Starter. Однако со временем мы постепенно отошли от этой рекомендации в сторону удалённого движка. В Zeebe мы и вовсе не поддерживаем использование встроенного движка.

В сегодняшнем блоге я хочу объяснить причины этого перехода и почему мы рекомендуем использовать удалённый движок. Однако сначала давайте разберёмся, почему встроенный движок изначально представлял собой привлекательный выбор, и отметим, что изменилось с течением времени. Если вам не интересна эволюция данного вопроса, вы можете пропустить историческую справку и перейти к сравнению архитектур движков.

Немного истории рекомендаций по архитектуре движков

Оглядываясь на десять лет назад, в 2012 году, популярными были серверы приложений Jakarta EE, а Jakarta EE всё ещё носила название J2EE. Большинство Java-приложений развертывались на таких серверах приложений. В Camunda мы сознательно обеспечили интеграцию с этими серверами приложений, предоставив контейнерный движок, даже для IBM Websphere, который использовался в крупных корпоративных аккаунтах. Эта интеграция была очень значимой, так как позволила разработчикам сосредоточиться на разработке своих процессных решений, а не на настройке движка рабочего процесса, управлении транзакциями и т. д. У нас были отличные интеграции: движок рабочего процесса мог легко использовать пул потоков или транзакции, управляемые сервером приложений. В то время контейнерный движок был стандартным решением.

Однако существовали и «повстанцы» Spring, выступавшие против J2EE (вспомните книгу 2004 года, положившую начало успеху Spring, «J2EE Development without EJB»). Эти разработчики использовали Spring и развёртывали свои приложения на Tomcat. Хотя на Tomcat имелся контейнерный движок, оказалось, что пользователи не желали возиться с установкой самого Tomcat, а предпочитали создавать одну самодостаточную конфигурацию (включая встроенный BPM-движок), которую можно было бы разместить на любом стандартном сервере Tomcat. Это решение оказалось гораздо более удачным в корпоративных средах, где пользователи получали предустановленный стандартный Tomcat, который нельзя было настраивать под свои нужды.

Хотя эта модель была популярной, у неё были свои проблемы. Например, возникали трудности с загрузкой классов при развертывании вашего приложения рядом с веб-приложениями Camunda. Кроме того, это приводило к запутанному смешиванию конфигураций в Tomcat и в самом приложении. Всё это способствовало появлению Spring Boot, где приложение является полностью самодостаточным. Это также совпало с идеями о микросервисах и развитием контейнеризации.

Около 2015 года группа энтузиастов создала Spring Boot Starter для Camunda, который уже в 2017 году стал официальным продуктом благодаря большому интересу со стороны сообщества. Вскоре он стал стандартной рекомендацией для новых проектов. Типичная архитектура выглядела как наша рекомендация по greenfield-архитектуре:

Однако в то же время появился паттерн external task, который быстро набрал популярность. Одним из важных факторов его успеха стало то, что большинство процессных решений в то время становились более сложными и уже не представляли собой одно самодостаточное приложение. Скорее, они координировали удалённые конечные точки и становились частью распределённой системы (например, в микросервисных архитектурах). В последние месяцы мы приложили много усилий, чтобы сделать external task стандартной моделью разработки, даже несмотря на то, что это пока немного неудобно. Тем не менее, это можно реализовать. Если рассмотреть Zeebe как BPM-движок в рамках Camunda Cloud, он использует только паттерн external task и при этом предоставляет разработчикам значительное удобство.

Используя external tasks, вы можете легко развернуть движок удалённо, вместо того чтобы встраивать его. Но почему это сейчас хорошая идея?

Общий тренд состоит в переходе к распределённым системам нового поколения, таким как Docker, Kubernetes и движении в сторону облака. Всё это интересно, поскольку упрощает получение ресурсов, необходимых вашему приложению, в виде сервисов. Вам нужна реляционная база данных? Вы просто развертываете её, либо в облаке, либо с помощью одной команды Docker. Ушли те времена, когда приходилось что-то устанавливать вручную. Всё автоматизировано, воспроизводимо, просто и надёжно.

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

В 2020 году мы определили новое решение, сосредоточенное исключительно на этом сценарии использования: Camunda Run. Идея состояла в создании самодостаточного BPM-движка, который можно легко настраивать и использовать в средах Docker или Kubernetes, без знания Java. Это позволяет запускать BPM-движок как сервис. Многие крупные клиенты уже используют такой подход для своих внутренних проектов, в качестве своего рода внутреннего облака. Мы также предлагаем собственный облачный сервис (на базе Zeebe).

Текущие рекомендации

Теперь мы стандартно рекомендуем для Camunda Platform 7 использовать удалённый движок. Более конкретно Camunda Run в качестве BPM-движка с использованием external tasks и REST API (обычно обёрнутого в клиент для вашего языка программирования). Вы можете найти это расширение от сообщества полезным, если разрабатываете на Java. Теперь наша рекомендация по архитектуре greenfield будет выглядеть следующим образом:

Этот стек также близок к тому, что вы бы использовали в Camunda Cloud:

Подход с удалённым движком значительно облегчает переключение между двумя архитектурами. Это позволяет вашей организации сосредоточиться на одном архитектурном стиле. И если вы когда-либо подумаете о миграции с Camunda Platform 7 на Camunda Cloud в будущем, этот стек существенно упростит этот процесс.

Теперь давайте рассмотрим плюсы и минусы встроенного движка в свете современных реалий.

Слабые стороны встроенного движка

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

Отсутствие изоляции между движком и приложением, что означает:

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

  • Библиотеки перемешаны: Приложение автоматически включает все зависимости BPM-движка, что может привести к конфликтам версий, которые не всегда легко разрешить.

  • Расширяемость ослабляет стабильность: Приложения со встроенной Camunda, имели множество возможностей для влияния на поведение ядра движка. Это могло повлиять на стабильность ядра или привести к уязвимостям, которые трудно диагностировать.

  • Необходимость полной сборки и повторного развертывания: Изменения в конфигурации движка рабочего процесса или обновления версий (даже патчей) могут потребовать полной пересборки и повторного развертывания приложения.

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

  • Сложнее начать и требуется больше знаний Java: Если вы профессионал в Spring Boot, использование Spring Boot Starter будет для вас естественным. Но в противном случае мы обнаружили, что это может быть очень сложно. Гораздо проще попросить людей запустить контейнер Docker или стартовать движок в облаке.

  • Отсутствие полиглотных сред: Встроенные движки могут поддерживать только один язык программирования. В случае с Camunda этот язык — Java. Современные архитектуры гораздо более полиглотные и должны поддерживать несколько языков.

  • Больше нагрузка на разработчиков: Встроенный движок возлагает на разработчиков ответственность за интеграцию и конфигурацию самого BPM-движка. Поскольку разработчики — это действительно ценный ресурс, лучше освободить их время насколько возможно. Кроме того, встроенный движок часто не может быть настроен извне в той степени, в которой это бы хотелось вашим специалистам по инфраструктуре, например, для оптимизации его под производственную среду.

Преимущества удалённого движка

Удалённый движок имеет несколько преимуществ, которые в основном устраняют вышеупомянутые слабости:

  • Слабая связанность: BPM-движок развёртывается и настраивается независимо от приложения и процессного решения. Проблемы можно легко локализовать в одном из компонентов, а уязвимости не распространяются на другие компоненты.

  • Улучшенное масштабирование: BPM-движок может масштабироваться независимо от кода приложения. Camunda может оптимизировать производительность ядра движка, поскольку имеет полный контроль над тем, что происходит в этой области.

  • Позволяет использовать ПО как услугу (SaaS): BPM-движок может работать как сервис для вас, либо в публичном облаке (например, Camunda Cloud), либо, возможно, как внутренний сервис (как это делают наши клиенты). В то же время вы можете разрабатывать свое приложение локально или на местах, так как приложения могут удалённо подключаться к BPM-движку.

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

В качестве примера давайте рассмотрим прототип, который был реализован у крупного автопроизводителя. Они использовали Apache Kafka и MongoDB. Для них было естественно иметь файл Docker Compose для запуска необходимых ресурсов, поэтому добавление двух строк для запуска Camunda казалось совершенно правильным. Затем они могли распределить работу. Один из специалистов по инфраструктуре занялся подключением Camunda к выбранному ими PostgreSQL и настройкой некоторых аспектов безопасности, в то время как разработчики сразу приступили к моделированию и выполнению процесса BPMN.

Удаленный движок требует использования паттерна external task, что приводит к дополнительным преимуществам, возникающим просто благодаря его применению:

  • Слабая связность по времени: Ваш связующий код (то, что мы называем «workers«) может некоторое время быть оффлайн; в этом случае задачи из BPM-движка будут просто ждать, пока подключение восстановится. Такой подход обеспечивает слабую связность по времени, позволяя компонентам работать независимо и повышая устойчивость системы. При этом не требуется использование брокера сообщений для управления взаимодействием между компонентами.

  • Полиглотные архитектуры (не-Java окружения): Делегаты Java работают только в Java, но внешние задачи позволяют использовать множество языков благодаря поддержке REST.

  • Слабая связность при имплементации: Worker является отдельным программным компонентом и не связан с BPM-движком. Это означает, что он может контролировать множество аспектов своей работы самостоятельно. Например, если вам нужно выполнять сервисную задачу, которая занимает несколько часов (например, транскодирование видео), это не станет проблемой. Если вы хотите ограничить количество параллельных вызовов сервиса до одного (например, по причинам лицензирования), вы можете легко управлять этим.

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

Некоторые мифы о удалённых движках

Вы можете ознакомиться с материалом «Как писать связующий код без Java-делегатов в Camunda Cloud», который развенчивает некоторые распространённые мифы, связанные с использованием внешних задачами с удалённым движком:

  • Вы все равно можете вызывать конечные точки ваших сервисов через любой протокол (например, REST, AMQP, Kafka).

  • Весь код worker’ов может находиться в одном Java-приложении.

  • Модель программирования оказывается удивительно похожей на Java- делегаты при использовании Spring.

  • Обработка исключений также может быть доверена BPM-движку.

  • Снижение производительности не столь велико.

Проблемы удалённого движка

Конечно, разработчики также сталкиваются с типичными проблемами при настройке удалённого движка. Давайте рассмотрим эти проблемы и способы их решения.

  • Удобство программной модели: Удалённая связь через REST или gRPC менее удобна для разработчиков, чем простое использование клиентской библиотеки на их языке программирования. Это можно смягчить, предоставив соответствующие клиентские библиотеки, которые скрывают детали удалённой связи, как, например, делает Zeebe для Spring, Java и других языков. Статья «Как писать связующий код без Java-делегатов в Camunda Cloud» даст вам хорошее представление о том, что имеется в виду.

  • Транзакции в удалённом режиме: С удалённым движком вы не можете разделять транзакции между вашим кодом и BPM-движком. Я посвятил этой теме отдельную статью: «Достижение согласованности без менеджеров транзакций».

  • Организация работы с удалённым ресурсом: Удалённый движок является отдельным ресурсом, программой или контейнером, которым необходимо управлять для работы вашего приложения. Благодаря облачным сервисам или Docker это может быть решено очень легко в наши дни и выглядит менее проблематичным, чем несколько лет назад. Вы также можете просто скачать и распаковать BPM-движок локально и запустить его на своём компьютере — для этого вам лишь установить Java.

  • Написание модульных тестов: Существует специфическая задача: вы хотите, чтобы модульные тесты выполнялись изолировано, без каких-либо зависимостей от окружения. Это можно решить с помощью проекта Testcontainers, но Zeebe также предоставляет «мини-движок», который может работать в процессе выполнения теста JUnit, полностью устраняя эту проблему в мире Java. Подробности можно найти в проекте zeebe-process-test. Возможно, другие языки программирования последуют этому примеру.

Заключение

Режим удалённого движка станет стандартом для будущих процессных решений. Это предоставляет множество преимуществ и соответствует современным подходам к построению программной архитектуры. Мы стремимся обеспечить такую же удобство для разработчиков и предложить сопоставимую программную модель, особенно в Camunda Cloud, но также планируем догнать её в Camunda Platform 7. Надеюсь, этот пост убедил вас в том, что это не только осознанное, но и очень обоснованное решение.

Подписывайтесь на Telegram канал BPM Developers. Рассказываем про бизнес процессы: новости, гайды,  полезная информация и юмор.

5 февраля в 14:00 мск пройдет презентация новой open source платформы OpenBPM. Регистрируйтесь и приходите.

Комментарии (0)