Статьи

Новый API персистентности KIE на 7.0

Этот пост представляет предстоящие слюни и API персистентности jBPM. Мотивация для создания API сохраняемости, который не должен быть привязан к JPA, поскольку постоянство в Drools и jBPM было до выпуска 7.0.0, состоит в том, чтобы обеспечить чистую интеграцию альтернативных механизмов постоянства с JPA. Хотя JPA — отличный API, он тесно связан с традиционной моделью СУБД с унаследованными от нее недостатками — сложность масштабирования и сложность получения хорошей производительности в любых масштабируемых системах. С новым API мы открыты для интеграции различных общих баз данных NoSQL, а также для создания специально разработанных механизмов персистентности для достижения оптимальной производительности и масштабируемости.

На момент написания этой статьи было сделано несколько реализаций — механизм JPA по умолчанию, две базовые реализации NoSQL-бэкенда от Inifinispan и MapDB, которые будут доступны в качестве вкладов, и одна сделанная на заказ реализация NoSQL, которая вскоре обсуждается в этом посте.

Изменения, внесенные в механизмы персистентности Drools и jBPM, его новые функции и то, как он позволяет создавать чистые новые реализации персистентности для компонентов KIE, являются основой для нового вскоре добавляемого экспериментального модуля интеграции MapDB. Существующая адаптация Infinispan была изменена с учетом новой структуры.

Благодаря этому рефакторингу у нас теперь могут быть другие реализации персистентности для KIE, не зависящие от JPA, если только наша конкретная реализация персистентности не основана на JPA. Это подразумевает, однако, ряд изменений:

Создание API-интерфейсов drools-persistence-api и jbpm-persistence-api

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

01
02
03
04
05
06
07
08
09
10
<dependency>
 <groupId>org.drools</groupId>
 <artifactId>drools-persistence-api</artifactId>
 <version>7.0.0-SNAPSHOT</version>
</dependency>
<dependency>
 <groupId>org.jbpm</groupId>
 <artifactId>jbpm-persistence-api</artifactId>
 <version>7.0.0-SNAPSHOT</version>
</dependency>

Первое, что следует упомянуть о классах в этом рефакторе, это то, что модель постоянства, используемая компонентами KIE для KieSessions, WorkItems, ProcessInstances и CorrelationKeys, больше не является классом JPA, а является интерфейсом. Эти интерфейсы:

  • PersistentSession
    : Для реализации JPA этот интерфейс реализован SessionInfo. Для будущей реализации MapDB используется MapDBSession.
  • PersistentWorkItem
    : Для реализации JPA этот интерфейс реализован с помощью WorkItemInfo и MapDBWorkItem для MapDB
  • PersistentProcessInstance
    Для реализации JPA этот интерфейс реализуется ProcessInstanceInfo и MapDBProcessInstance для MapDB.

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

Реакторы PersistenceContext, ProcessPersistenceContext и TaskPersistenceContext

Интерфейсы контекстов персистентности в версии 6 зависели от реализаций модели JPA. Чтобы работать с другими механизмами персистентности, их необходимо было реорганизовать для работы с моделью времени выполнения (ProcessInstance, KieSession и WorkItem, соответственно), построить реализации локально и иметь возможность возвращать нужный элемент, если этого требуют другие компоненты ( ProcessInstanceManager, SignalManager и т. Д.)

Кроме того, для таких компонентов, как TaskPersistenceContext, в коде службы задач использовалось несколько динамических запросов HQL, которые не могли бы быть реализованы в другой модели персистентности. Чтобы избежать этого, они были изменены, чтобы использовать определенные механизмы, более связанные с критериями. Таким образом, различные объекты фильтрации могут по-разному использоваться другими механизмами персистентности для создания требуемых запросов.

Рефактор модели задачи

То, как текущая модель задач соотносит задачи и объекты контента, комментариев, вложений и крайних сроков, также зависело от того, как JPA хранит эту информацию, или, точнее, от того, как ORM связывают эти типы. Поэтому был введен рефакторинг интерфейса контекста персистентности задачи, чтобы сделать связь между компонентами для нас, если это необходимо. Большинство методов все еще там, и различные таблицы все еще могут использоваться, но если мы просто хотим использовать Задачу, чтобы связать все вместе как объект (как это сделала бы реализация NoSQL), мы теперь можем. Для реализации JPA он все еще связывает объект по ID. Для других механизмов персистентности, таких как MapDB, целесообразно добавить подобъект к объекту задачи, который он может извлечь из внутренних индексов.

Еще одна вещь, которая была изменена для модели задачи, это то, что раньше у нас были разные интерфейсы для представления Задачи (Task, InternalTask, TaskSummary и т. Д.), Которые были несовместимы друг с другом. Для JPA это было нормально, потому что они представляли разные виды одних и тех же данных.

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

(Но для других типов реализации, таких как MapDB, где всегда было бы дешевле получить объект Task напрямую, чем создавать другой объект, нам нужно было иметь возможность вернуть Task и заставить его работать в качестве TaskSummary, если интерфейс запрашивает это. Все интерфейсы теперь совпадают для одинаковых имен методов, чтобы учесть это.)

Расширяемый TimerJobFactoryManager / TimerService

В версии 6 единственные возможные реализации TimerJobFactoryManager были связаны в конструкции значениями перечисления TimeJobFactoryType. Был проведен рефакторинг для расширения существующих типов, чтобы позволить динамически добавлять другие типы фабрик заданий таймера

Создание собственной настойчивости. Дело MapDB

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

  • org.kie: Drools-сохранение-mapdb
  • org.kie: jbpm-сохранение-mapdb
  • org.kie: jbpm-человек-проблемно-mapdb

Это предназначено для реализации всей модели Task с использованием классов реализации MapDB. Любой, кто хочет иметь другой тип реализации для компонентов KIE, может просто выполнить следующие шаги, чтобы начать реализацию:

  1. Создание модулей для смешивания проектов API постоянства с зависимостями механизма реализации постоянства.
  2. Создать реализацию модели на основе заданных интерфейсов со всеми необходимыми конфигурациями и аннотациями
  3. Создайте свои собственные (Process | Task) классы PersistenceContext (Manager), чтобы реализовать способ хранения постоянных объектов.
  4. Создайте своих собственных менеджеров (WorkItemManager, ProcessInstanceManager, SignalManager) и фабрики со всеми необходимыми дополнительными шагами для сохранения вашей модели.
  5. Создайте свою собственную реализацию KieStoreServices, которая создает сеанс с необходимой конфигурацией и добавляет его в путь к классам.

Вы не одиноки: дело MultiSupport

MultiSupport — это компания из Дании, которая использовала этот рефакторинг для создания собственной персистентной реализации. Они предоставляют продукт архивации, который ориентирован на создание системы поиска архивов O (1), и очень заинтересован в том, чтобы заставить их внутренние процессы работать, используя тот же механизм сохранения, который они использовали для своих архивов.

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

В MultiSupport мы использовали API персистентности для создания специализированного хранилища на основе нашего внутреннего механизма хранения — наша мотивация заключалась в том, чтобы обеспечить неограниченную масштабируемость, расширенные возможности поиска, простое распространение и производительность, которой мы изо всех сил пытались достичь с помощью реализации JPA. Мы думаем, что это можно использовать как демонстрацию того, насколько далеко вы можете зайти с новым API персистентности. С текущей реализацией JPA и выделенным SQL-сервером мы достигли начальной производительности менее 10 операций «запуска процесса» в секунду, теперь с выходом следующей версии мы на одном сервере приложений имеем производительность
более чем в 10 раз