ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Flowable 引擎技术调研

2021-10-18 12:01:25  阅读:1003  来源: 互联网

标签:RU Flowable 流程 引擎 HI ACT Execution 调研


主要概念

BPM

Business Process Management,业务流程管理

BPMN

Business Process Modeling Notation,BPMN是一个广泛接受与支持的,展现流程的注记方法:OMG BPMN标准,BPMN2.0正式版本于2011年1月3日发布,常见的工作流引擎如:Activiti、Flowable、jBPM 都基于 BPMN 2.0 标准。

事件

事件(event)通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。例如:

顺序流

顺序流(sequence flow)是流程中两个元素间的连接器。在流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。用从源元素指向目标元素的箭头表示。例如:

网关

网关(gateway)用于控制执行的流向(或者按BPMN 2.0的用词:执行的 “标志(token)” )。网关用其中带有图标的菱形表示。例如:

活动

活动(Activity)用于表示需要执行的行为,任务用带有图标的圆角矩形表示。例如:

CMMN

Case Management Model and Notation,CMMN具有与BPMN不同的基本范例,CMMN没有顺序的流程,它以某种状态对案例建模。

DMN

Decision Model and Notation,DMN的目的是提供一个模型决策结构,从而使组织的策略可以用图形清晰的地描绘出来,这个标准可以用于实现规则引擎。

概览

Flowable是由Activiti的原核心开发人员,基于Activiti5开发的。

Flowable提供了多层次的解决方案

Web App

通过直接搭建Web应用,可直接获得产品化的解决方案。

Flowable IDM: 身份管理应用。为所有Flowable UI应用提供单点登录认证功能,并且为拥有IDM管理员权限的用户提供了管理用户、组与权限的功能。

Flowable Modeler: 让具有建模权限的用户可以创建流程模型、表单、选择表与应用定义。

Flowable Task: 运行时任务应用。提供了启动流程实例、编辑任务表单、完成任务,以及查询流程实例与任务的功能。

Flowable Admin: 管理应用。让具有管理员权限的用户可以查询BPMN、DMN、Form及Content引擎,并提供了许多选项用于修改流程实例、任务、作业等。

REST API

通过搭建REST服务,上层系统可通过调用HTTP API,使用引擎能力。

Flowable BPMN User Guide - REST API

Java API

Flowable提供了一套完整的API,供使用方调用,所有的服务都是无状态的,意味着依赖这套API的服务天然可在分布式环境进行部署。通过直接依赖jar包进行集成,并在各层都留出了接口,使用时可自行灵活扩展。结合使用场景,建议使用Java API进行开发,本文也将重点介绍基于该方式集成的调研结果。

类名说明
ProcessEngine引擎API的总入口
RepositoryService部署(deployments) 与 流程定义(process definitions)
RuntimeService启动新流程实例、读取与存储流程变量(process variables) 、查询流程实例与执行(Execution)
TaskService查询任务、分配执行用户(assignee) 、认领任务(claim) 、完成任务(complete)
HistoryService提供查询历史数据的能力
IdentityService用于管理组与用户,可选(引擎运行时并不做用户校验)
FormService表单相关服务,可选(表单不一定要嵌入流程定义)
ManagementService用于读取数据库表与表原始数据的信息,也提供了对作业(job)的查询与管理操作
DynamicBpmnService可用于动态修改流程定义中的部分内容,而不需要重新部署

典型场景

以如下“请假流程”为例,演示Flowable API使用方式,为减少干扰,此处特意没有与Spring集成,以演示最原生的API调用。

⬇️ 符合BPMN 2.0标准的流程图

⬇️ holiday-request.bpmn20.xml 文件内容,及上图所对应的数据文件

部署流程定义

代码逻辑

数据变更

⬇️ ACT_RE_DEPLOYMENT (Deployment) 对应生成了一条记录,表示本次部署。

⬇️ ACT_GE_BYTEARRAY (EngineResource) 生成了两条记录,对应两个资源文件,BYTES_字段保存了文件的原始内容。

⬇️ ACT_RE_PROCDEF (ProcessDefinition) 生成了三条记录,对应到XML中定义的三个流程。

启动流程实例

代码逻辑

数据变更

运行时相关表(ACT_RU_*):只保留当前运行时数据

⬇️ ACT_RU_ACTINST(ActivityInstance) :“活动”数据,包含了流程经过的所有节点(包括连线在内,可以理解为流程经过的全部XML Element)。

⬇️ ACT_RU_EXECUTION(Execution) :“执行”数据,标示了当前的分支路径,一般是遇到网关或并行流程时,会分裂为多个执行,与分裂前的Execution会存在父子关系,只会保留当前正在进行中的Execution。

Q:为什么初始有两个Execution?

A:Flowable 默认会创建一个最父级Execution对象,用来表示“流程实例(ProcessInstance)”,其他表中的PROC_INST_ID,关联的记录实际也是这条ROOT级别的Execution对象。

Q:多条并行的分支路径时,Execution会如何生成?

A:会拆分为多个Execution,并行网关前的其中一个Execution(最后触发分支的这个)会继续延展到网关后的第一个分支,其他的分支会创建出新的Execution。

⬇️ ACT_RU_TASK(Task) :“任务”数据,即用户的代办事项,只会保留当前未完成的任务。

⬇️ ACT_RU_VARIABLE(VariableInstance) :“变量”数据,当前流程实例所设置的变量。

也可以通过setVariableLocal方法将变量绑定在Execution/Task上,作用域相应降低,Local的变量会在流程离开当前作用域时被删除。

Q:如果流程运行到某个表达式,但表达式依赖的变量没有设置会怎么样?

A:会直接抛异常,同时会回滚本次事务。

⬇️ ACT_RU_IDENTITYLINK(IdentityLink) :“身份关联”数据,标志了用户和组在本次流程中的角色。

历史记录相关表(ACT_HI_*),保留全部历史

⬇️ ACT_HI_ACTINST(HistoricActivityInstance) ,与ACT_RU_ACTINST对应。

⬇️ ACT_HI_PROCINST(HistoricProcessInstance) ,流程实例历史。

Q:为什么这个表没有对应的ACT_RU_*表?

A:这个表的数据实际对应的就是ACT_RU_EXECUTION表中,PARENT_ID为NULL数据,可以理解为一次流程Execution的最父级,即为一个ProcessInstance对象。

⬇️ ACT_HI_TASKINST(HistoricTaskInstance) ,与ACT_RU_TASK对应,区别是任务结束后数据仍会保留。

⬇️ ACT_HI_VARINST(HistoricVariableInstance) ,与ACT_RU_VARIABLE对应。

⬇️ ACT_HI_IDENTITYLINK(HistoricIdentityLink) ,与ACT_RU_IDENTITYLINK对应。

当前位置

完成任务

代码逻辑

数据变更

运行时相关表(ACT_RU_*):只保留当前运行时数据

⬇️ ACT_RU_ACTINST(ActivityInstance)

⬇️ ACT_RU_EXECUTION(Execution)

⬇️ ACT_RU_TASK(Task)

⬇️ ACT_RU_VARIABLE(VariableInstance)

⬇️ ACT_RU_IDENTITYLINK(IdentityLink)

历史记录相关表(ACT_HI_*),保留全部历史

⬇️ ACT_HI_ACTINST(HistoricActivityInstance)

⬇️ ACT_HI_PROCINST(HistoricProcessInstance)

无变更

⬇️ ACT_HI_TASKINST(HistoricTaskInstance)

⬇️ ACT_HI_VARINST(HistoricVariableInstance)

⬇️ ACT_HI_IDENTITYLINK(HistoricIdentityLink)

当前位置

结束流程

代码逻辑

数据流转

运行时相关表(ACT_RU_*):只保留当前运行时数据

  • 本次流程实例相关的数据均被清空

历史记录相关表(ACT_HI_*),保留全部历史

⬇️ ACT_HI_ACTINST(HistoricActivityInstance)

⬇️ ACT_HI_PROCINST(HistoricProcessInstance)

⬇️ ACT_HI_TASKINST(HistoricTaskInstance)

⬇️ ACT_HI_VARINST(HistoricVariableInstance)

  • 无变化

⬇️ ACT_HI_IDENTITYLINK(HistoricIdentityLink)

  • 无变化

源码分析

调用层次

  • Flowable将所有执行逻辑抽象为“命令”(Command),并通过CommandExecutor对Command对执行调用,CommandExecutor通过职责链模式,对Command包装了多层拦截器,默认拦截器的功能包含了:构建本次命令执行的上下文CommandContext、限定事务边界、打印日志等。
  • 通过依赖关系,CommandContext -> (engineConfigurations, sessionFactories),Command中的逻辑可以间接获取到下层的Manager对象以及DBSession对象,进行相应逻辑的实现。

流转逻辑

  • Flowable将流程源文件的内容,统一解析为Process对象,将各种节点抽象为FlowElment,并缓存在进程中,通过在Process对象上进行查找,来确认流程的当前节点的类型,以及后续节点的类型,这套逻辑都在内存中完成,理论上会比较高效(见左图)。
  • Flowable实现了一套类似深度优先的机制,将涉及到流程流转的逻辑,统一抽象为“操作”AbstractOperation,CommandInvoker通过对操作队列的顺序执行,完成流程节点的流转,直至当前的各个Execution都达到“等待状态”(见右图)。

仍然以以下流程为例,本次换成对请假申请进行拒绝。

具体流转步骤如下

编号当前操作节点流转数据变更
1TriggerExecutionOperationUserTask
2TakeOutgoingSequenceFlowsOperationUserTask -> SequenceFlowActivityInstance:UserTask 标记为结束Execution:变更当前节点为 SequenceFlow
3ContinueProcessOperationSequenceFlow -> ExcusiveGateway ->SequenceFlowActivityInstance:创建SequenceFlow并标记为结束Execution:变更当前节点为ExcusiveGatewayActivityInstance:创建ExcusiveGateway并标记为开始Execution:变更当前节点为SequenceFlow
4TakeOutgoingSequenceFlowsOperationSequenceFlowActivityInstance:标记ExcusiveGateway为结束
5ContinueProcessOperationSequenceFlow -> ServiceTaskActivityInstance:创建SequenceFlow并标记为结束Execution:变更当前节点为ServiceTaskActivityInstance:创建ServiceTask并标记为开始。
6TakeOutgoingSequenceFlowsOperationServiceTask -> SequenceFlowActivityInstance:标记ServiceTask记录为结束Execution:变更当前节点为SequenceFlow
7ContinueProcessOperationSequenceFlow -> EndEventActivityInstance:创建SequenceFlow并标记为结束Execution:变更当前节点为EndEventActivityInstance:创建EndEvent并标记为开始
8TakeOutgoingSequenceFlowsOperationEndEventActivityInstance:标记EndEvent记录为结束
9EndExecutionOperation删除本次运行时的相关数据

注:该例子流程比较简单,如果存在多个并行分支,Execution则会分裂出多个,通过这套机制,可以比较好的降低复杂性。

异步执行

Flowable 实现了一套异步执行器,用于的将一些逻辑切换为异步进行执行。

定时器(Timers)

保存在ACT_RU_TIMER_JOB表中,并带有给定的到期日期。异步执行器中有一个线程,周期性地检查是否有需要触发的定时器。当需要触发定时器时,从JOB表中移除该定时器,并创建一个异步作业(async job)。

异步延续 (Asynchronous Continuations)

Flowable 支持将某些任务节点配置为异步执行,只需要按以下方式配置节点属性,即可使任务的执行切换为异步执行。Flowable默认通过DB实现了一个类似消息队列的机制,引擎通过启动线程池来完成消息的消费,Flowable也留出了扩展性,可以替换为使用真实的消息队列实现异步。

 <serviceTask id="service1" name="Generate Invoice"

    flowable:class="my.custom.Delegate"

    flowable:async="true" />
复制代码

异步历史(Asynchronous History)

Flowable 支持将History数据的写入配置为异步,只需要配置isAsyncHistoryEnabled=true,即可将历史数据的写入切换为异步写入,缩短客户端的等待时间。附:flowable异步历史性能基准测试

事件机制

  • Flowable实现了一套标准的事件机制,并在支持对多种事件进行监听,当Listener执行失败时也支持事务的回滚(可选),详见:3.18. 事件处理器
  • 通过这套机制,可以在流程进行的同时,通过监听相应的时间,对业务系统进行额外操作。

变量作用域

引擎可在多个级别设置变量,作用域各不相同,设置方法如下:

RuntimeService
   void setVariable(String executionId, String variableName, Object value);
   void setVariableLocal(String executionId, String variableName, Object value);

TaskService
   void setVariable(String taskId, String variableName, Object value);
   void setVariableLocal(String taskId, String variableName, Object value);

VariableScope
   void setTransientVariable(String variableName, Object variableValue);
   void setTransientVariableLocal(String variableName, Object variableValue);

// setVariables,setVariableLocals 为对应函数的批量形式,以上省略
复制代码

作用域如下

方法说明
RuntimeService.setVariable变量关联最顶级Execution,当前流程内的Execution/Task 均可以获取到这些变量。
RuntimeService.setVariableLocal变量关联指定的ExecutionId,只有对应的Execution(包括子执行)及所属的Task可以获取到这些变量。
TaskService.setVariable同 RuntimeService.setVariable。
TaskService.setVariableLocal变量关联指定的TaskId,只有对应的Task可以获取到这些变量。
VariableScope.setTransientVariable不持久化,仅存在于内存中,会在下一个“等待状态”消失,等待状态意味着流程实例会持久化至数据存储中。等待状态可以是用户任务/异步活动。
VariableScope.setTransientVariableLocal不持久化,变量作用域取决于是对哪个对想设置。

以下代码用于验证

代码输出结果

 Execution 15004 variables:
     var_local_execution_15004: 1
     var_local_execution_15001: 1
     var_execution_15004: 1
     var_execution_15001: 1
     var_task_15008: 1

 Execution 15001 variables:
     var_local_execution_15001: 1
     var_execution_15004: 1
     var_execution_15001: 1
     var_task_15008: 1

 Task 15008 variables:
     var_local_execution_15004: 1
     var_local_execution_15001: 1
     var_execution_15004: 1
     var_local_task_15008: 1
     var_execution_15001: 1
     var_task_15008: 1
复制代码

持久化数据

扩展性

  • Flowable 在各个层次均留出了接口,用于扩展,通过使用ProcessEngineConfiguration进行配置,可以轻松替换各种实现,如:

    • 可通过替换 DeploymentDataManager 接口的实现,将底层存储替换为其他任意存储介质。
    • 可通过替换 IdGenerator 接口的实现,将ID生成器替换为其他类型。
  • Flowable 各模块解耦比较充分,引擎核心并不依赖一些上层应用,比如身份相关模块、表单相关模块,可以只使用引擎做状态流转,但用户身份等仍然使用公司的主数据。

性能

缓存机制

通过对源码的分析,Flowable中的缓存大致分为两类:

  1. 对流程定义(ProcessDefinition)这类数据的缓存,因为变更较少且访问频繁,将数据解析后常驻缓存在了进程中,且因每次部署时都是重新插入新的数据,所以不会存在有一致性的问题。
  2. 对于各数据实体的缓存,Flowable 设计了生命周期为一次命令的缓存,这类缓存能有效降低一次调用中相同数据对DB的多次查询,并随着CommandContext的销毁而销毁。

同时,Flowable留出了接口,可以比较轻松的进行扩展,将缓存替换成Redis这类集中式缓存。

长流程

因为流程只能单向流动,Flowable的机制保证了,即使流程中节点很多,也只需要加载当前节点附近的节点,并不会因为处在一个长流程中,而使每一步的耗时线性增加。

吞吐量

Flowable没有一些NIO、Reative相关的实现,所以吞吐量取决于一次请求中的IO耗时于线程数配置的。

多租户

原生支持

Flowable原生支持多租户,如“典型场景”中的使用方式,只需要在调用API时传入tenantId,即支持在某个租户下进行操作,体现在数据上,便是各实体均有TENANT_ID字段用于标志租户。

数据隔离

Flowable默认将所有租户都放在相同的表中,用TENANT_ID区分,进行数据隔离。但由于Flowable的高度可定制,可以通过重载配置类,将数据分配到不同database,进行保存。官方也提供了对应的配置类实现:MultiSchemaMultiTenantProcessEngineConfiguration。

数据迁移

当某个租户需要从集群迁移出来,进行独立集群部署/私有化部署时,可通过数据库表的TENANT_ID导出对应数据,进行相应部署。这部分目前没有发现官方有现成的迁移工具,但理论上复杂性并不高,主要需要关注如何平滑迁移集群流量这类常见问题。

官方同样提供了changeDeploymentTenantId这种一键替换某个租户的TENANT_ID的方法,这个在数据量大的情况下可能会导致事务很大,个人建议这类操作还是自行控制更合适。

相关竞品

Activiti

目前的最新版 7.1.x,从2016年与Flowable分家之后,主要方向在云化;而Flowable主要专注于升级引擎的核心,Activiti 与 Flowable 个人更推荐后者。

Camunda

相关的资料比较少,是三个中最早支持CMMN、DMN的引擎,功能上的对比可以参考本文中的对比表格:工作流选型专项,Camunda or flowable or?(未完全求证),Camunda是否比Flowable更合适还有待调研。


作者:孔咯
链接:https://juejin.cn/post/7002503394707374111
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:RU,Flowable,流程,引擎,HI,ACT,Execution,调研
来源: https://blog.csdn.net/u010365819/article/details/120823754

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有