多租户 Multitenancy
总的来说,多租户是一个软件为多个不同组织提供服务的概念。其核心是数据是隔离的,一个组织不能看到其他组织的数据。在这个语境中,一个这样的组织(或部门、团队,等等)被称为一个租户(tenant)。
请注意它与多实例安装方式有本质区别。多实例安装是指每一个组织都分别运行一个Flowable流程引擎实例(且使用不同的数据库账户)。尽管Flowable比较轻量级,运行一个流程引擎实例不会花费太多资源,但多实例安装仍然增加了复杂性与维护量。但是,在某些使用场景中,多实例安装可能是正确的解决方案。
Flowable中的多租户主要围绕着隔离数据实现。要注意Flowable并不强制多租户规则。这意味着当查询与使用数据时,并不会验证进行操作的用户是否属于正确的租户。这应该在调用Flowable引擎的层次实现。Flowable确保可以存储租户信息,并在获取流程数据时使用。
在Flowable流程引擎中部署流程定义时,可以传递一个租户标识符(tenant identifier)。这是一个字符串(例如一个UUID,部门id,等等……),限制为256个字符长,唯一标识租户:
repositoryService.createDeployment() .addClassPathResource(...) .tenantId("myTenantId") .deploy();
在部署时传递一个租户id带有下列含义:
-
部署中包含的所有流程定义都将从该部署集成租户标识符。
-
从这些流程定义启动的所有流程实例都将从流程定义继承租户标识符。
-
在执行流程实例时,运行时创建的所有任务都将从流程实例继承租户标识符。独立任务也可以有租户标识符。
-
执行流程实例时创建的所有执行都将从流程实例继承租户标识符。
-
触发一个信号抛出事件(在流程内或通过API)时可以提供一个租户标识符。这个信号将只在该租户的上下文中执行:也就是说,如果有多个使用相同名字的信号捕获事件,只会调用带有正确租户标识符的事件。
-
所有作业(定时器与异步操作)要么从流程定义(例如定时器启动事件),要么从流程实例(运行时创建的作业,例如异步操作)继承租户标识符。这可以用于在自定义作业执行器中为部分租户设置优先级。
-
所有历史实体(历史流程实例、任务与活动)都从其对应的运行时对象继承租户标识符。
-
另外,模型也可以有租户标识符(模型在例如Flowable Modeler存储BPMN 2.0模型的时候使用)。
为了使用流程数据上的租户标识符,所有查询API都可以通过租户过滤。例如(也可以使用其他实体的对应查询实现替换):
runtimeService.createProcessInstanceQuery() .processInstanceTenantId("myTenantId") .processDefinitionKey("myProcessDefinitionKey") .variableValueEquals("myVar", "someValue") .list()
查询API也可以使用like语义通过租户标识符过滤,也可以过滤掉没有租户标识符的实体。
重要的实现细节:由于数据库的原因(更确切地说,对唯一约束中null的处理),默认的代表没有租户的租户标识符为空字符串。(流程定义key,流程定义版本,租户标识符)的组合需要是唯一的(通过数据库约束检查)。也请注意租户标识符不能设置为null,不然会影响查询,因为某些数据库(Oracle)将空字符串当做null值(这就是为什么.withoutTenantId查询不检查空字符串还是null)。这意味着同一个流程定义(有相同的流程定义key)可以为多个租户部署,每一个租户都有他们自己的版本。并不会影响未使用租户时的使用方式。
请注意上面所说都不与在集群中运行多个Flowable实例冲突。
[试验性] 可以调用repositoryService的changeDeploymentTenantId(String deploymentId, String newTenantId)方法修改租户标识符。这将修改每一处之前继承的租户标识符。在从非多租户环境迁移至多租户配置时很有用。