IT虾米网

Activiti工作流引擎多租户方案

mate10pro 2018年06月07日 编程语言 4022 0

Activiti租户也就是TENANT_ID_(tenantId)。该值主要用于记录启动的流程实例归属于哪个系统,比如a,b,c三个系统都有一个请假流程并且数据存储在同一个数据库,这个时候就应该考虑如何区分这三个流程了。

本文会详细讲解新的组合架构功能,洒上一些真实工作代码示例 !

1.1  多租户共享数据库

Activiti5.15版本中增加了多租户的概念,该功能主要用于数据共享在一个数据库的使用场景。一个或者多个的引擎但是他们使用的数据库为同一个。因此操作的时候需要区分这些数据(部署的流程资源)的来源,以方便程序后续的处理。因为只需要将tenantId理解为一个标记即可,其本身也没有更多的含义,仅仅是标记而已。

比如下图中的例子两个相同的流程定义key但是系统的来源不同。这个时候引擎会使用tenantId字段来确保数据不会混乱 。


 

上面的例子优点:部署的时候比较方便,只需要在启动流程实例的同时设置tenantId值即可。

缺点:就是在随后的操作中需要时刻牢记住tenantId。如果不传递该值或者传递错误了,那么风险就很大了。而且所有引擎共享一个数据库也可能会造成库中的数据激增以及庞大。这样当数据库达到一定的规模的时候,查询起来也确实有点吃力。

既然上述的方法有点瑕疵或者我们不想使用共享方式操作数据库,换言之每一个引擎使用自身的数据库,这样每一个引擎之间的数据是完全隔离的,相互之间不需要知道。如下图所示


在这样的需求中,每一个租户可以有不同的资源配置或者他们之间相互不需要知道自己的存在。这样每个引擎的性能会大大的提升。这样设计的好处是:引擎之间是相互隔离的。缺点就是:配置更复杂、每一个引擎实例都会占用一定的内存或者资源,并且你根本不用关系当前租户所使用的上下文以及路由组件。

 

1.2 多引擎多租户

开发人员使用的时候,往往希望更少的配置达到更好的效果,因此Activiti提供了多引擎多租户的功能,一个引擎实例支撑整个(或者多喝)数据库的操作。那么引擎是如何处理的呢?一个引擎操作多个数据库:第一需要有路由规则,比如a租户的存在在a库,b租户的数据存储在b库等等。


通过上图可以知道:通过一个引擎来管理和配置API能完全的达到效果,但不同的地方是数据之间是相互隔离的(类似多租户多引擎,但其实只有一个引擎来工作)。这样开发人员只需要配置和管理不同的数据库即可。引擎会自动根据tenantId查找到其对应的资源。


下面看下多租户单引擎的架构 :

建立流程引擎非常的简单如下所示:

config = new MultiSchemaMultiTenantProcessEngineConfiguration(tenantInfoHolder); 
config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_H2); 
config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE); 
config.registerTenant("alfresco", createDataSource("jdbc:h2:mem:activiti-mt-alfresco;DB_CLOSE_DELAY=1000", "sa", "")); 
config.registerTenant("acme", createDataSource("jdbc:h2:mem:activiti-mt-acme;DB_CLOSE_DELAY=1000", "sa", "")); 
config.registerTenant("starkindustries", createDataSource("jdbc:h2:mem:activiti-mt-stark;DB_CLOSE_DELAY=1000", "sa", "")); 
processEngine = config.buildProcessEngine(); 

上述代码看起来与常规的引擎创建过程非常的类似。最显著的区别就是我们使用引擎注册租户。每一个租户需要一个租户的唯一标识值以及数据源的配置。既然存在数据源当然需要对其进行配置了。这就意味着我们可以按照自己的实际情况配置一些数据池子。

路由规则需要配置哪些标识连接到哪些数据库,从TenantInfoHolder实例获取即可。

TenantInfoHolder是一个接口,这个需要自己实现,具体的使用取决于自己入户管理用户以及租户 。


 下面演示DummyTenantInfoHolder的使用:

 

private void setupTenantInfoHolder() { 
   DummyTenantInfoHolder tenantInfoHolder = new DummyTenantInfoHolder(); 
   tenantInfoHolder.addTenant("alfresco"); 
   tenantInfoHolder.addUser("alfresco", "joram"); 
   tenantInfoHolder.addUser("alfresco", "tijs"); 
   tenantInfoHolder.addUser("alfresco", "paul"); 
   tenantInfoHolder.addUser("alfresco", "yvo"); 
   tenantInfoHolder.addTenant("acme"); 
   tenantInfoHolder.addUser("acme", "raphael"); 
   tenantInfoHolder.addUser("acme", "john"); 
   tenantInfoHolder.addTenant("starkindustries"); 
   tenantInfoHolder.addUser("starkindustries", "tony"); 
   this.tenantInfoHolder = tenantInfoHolder; 
 } 

我们现在需要启动一些流程实例(任意一个流程即可)。同时需要做的就是切换当前的租户标识,进而观察数据库数据的变化。

当然了我们也可以动态的注册和移除租户。如下所示:

config.registerTenant("dailyplanet", createDataSource("jdbc:h2:mem:activiti-mt-daily;DB_CLOSE_DELAY=1000", "sa", ""));

由于上述涉及到的代码比较多,可以进qq群129123599进行下载上述的demo进行演示。

1.3 使用建议

对于多引擎多租户的使用需要认真考虑,其路由规则决定了数据将会存储在那个数据库,如果路由规则书写的不好,容易造成数据转发到一个库,就会造成某一个数据库的数据特别多,而其他的数据库没有数据或者数据少,造成数据倾斜

评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!