activiti 多租户

我们过去听到的一项功能请求是以多租户方式运行Activiti引擎,使租户的数据与其他数据隔离。 当然,在某些云/ SaaS环境中,这是必须的。

几个月前,波恩大学的学生拉斐尔·吉伦(Raphael Gielen)与我接触,他正在撰写有关Activiti多租户的硕士学位论文。 几周前,我们在一个共同工作的咖啡馆聚会,反弹想法,并为租户一起破解了具有数据库模式隔离的第一个原型。 很有趣 :-)。

无论如何,我们一直在完善和完善该代码,并将其提交给Activiti代码库。 让我们在下面的前两个部分中了解使用Activiti进行多租户的现有方法。 在第三部分中,我们将深入研究新的多租户多模式功能,其中包含一些实际工作的代码示例!

共享数据库多租户

Activiti已经有一段时间可以支持多租户了(从5.15版本开始)。 所采用的方法是共享数据库 :拥有一个(或多个)Activiti引擎,并且它们都进入同一个数据库。 数据库表中的每个条目都有一个租户标识符 ,最好将其理解为该数据的一种标记。 然后,Activiti引擎和API会读取并使用该租户标识符在租户的上下文中执行其各种操作。

例如,如下图所示,两个不同的租户可以具有使用相同密钥的流程定义。 引擎和API确保没有数据混合。

这种方法的好处是部署简单,因为与设置“常规” Activiti引擎没有区别。 缺点是您必须记住使用正确的API调用(即那些考虑了租户标识符的调用)。 而且,它与任何具有共享资源的系统都存在相同的问题:租户之间总是存在对资源的竞争。 在大多数用例中,这很好,但是有些用例不能以这种方式完成,例如为某些租户提供更多或更少的系统资源。

多引擎多租户

自Activiti的第一个版本以来,另一种可能的方法就是为每个租户简单地拥有一个引擎实例:

在此设置中,每个租户可以具有不同的资源配置,甚至可以在不同的物理服务器上运行。 当然,此图中的每个引擎可以是多个引擎,以提高性能/故障转移/等等。 现在的好处是,资源是为租户量身定制的。 缺点是设置比较复杂(多个数据库架构,每个租户都有不同的配置文件,等等)。 每个引擎实例都将占用内存(但是Activiti会占用很少的内存)。 另外,您无需编写一些路由组件 ,就可以以某种方式知道当前租户的上下文并路由到正确的引擎。

多架构多租户

Activiti多租户故事的最新添加是在两周前添加的(这是commit ),同时是版本5和6的添加。这里,每个租户都有一个数据库(模式),但是只有一个引擎实例。 再次,在实践中,可能有多个用于性能/故障转移/等的实例,但是概念是相同的:

好处显而易见:只有一个引擎实例可以管理和配置,而且API与非多租户引擎完全相同。 但最重要的是,租户的数据与其他租户的数据完全分开。 缺点(类似于多引擎多租户方法)是有人需要管理和配置不同的数据库。 但是复杂的引擎管理已不复存在。

我上面链接到的提交还包含一个单元测试 ,该测试显示了多模式多租户引擎的工作方式。

构建流程引擎很容易,因为有一个MultiSchemaMultiTenantProcessEngineConfiguration可抽象出大多数细节:

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();

这看起来与启动常规Activiti流程引擎实例非常相似。 主要的区别是,我们在注册与发动机租户。 每个租户都需要添加其唯一的租户标识符和数据源实现。 当然,数据源实现需要有自己的连接池。 这意味着您可以根据使用情况有效地为某些租户提供不同的连接池配置。 Activiti引擎将确保已创建或验证每个数据库架构都是正确的。

魔术以使这一切工作是TenantAwareDataSource 。 这是一个javax.sql.DataSource实现,它根据当前租户标识符委托给正确的数据源。 此类的思想在很大程度上受到Spring的AbstractRoutingDataSource (站在其他开源项目的肩膀上!)的影响。

通过从TenantInfoHolder实例获取当前的租户标识符来完成到正确数据源的路由。 如您在上面的代码片段中所看到的,在构造MultiSchemaMultiTenantProcessEngineConfiguration时,这也是必需的参数。 TenantInfoHolder是您需要实现的接口,具体取决于您环境中用户和租户的管理方式。 通常,您将使用ThreadLocal来存储由某些安全过滤器填充的当前用户/租户信息(类似于Spring Security)。 该类有效地充当下图中的路由组件”:

在单元测试示例中,我们确实使用了ThreadLocal来存储当前的租户标识符 ,并用一些演示数据填充它:

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;}

现在,我们开始一些流程实例,同时还要切换当前的租户标识符。 在实践中,您必须想象有多个线程随请求一起进入,它们将根据登录的用户设置当前的租户标识符:

startProcessInstances("joram");
startProcessInstances("joram");
startProcessInstances("raphael");
completeTasks("raphael");

上面的startProcessInstances方法将使用标准Activiti API设置当前用户和租户标识符,并启动几个流程实例, 就好像根本没有多租户一样completeTasks方法类似地完成了一些任务)。

同样很酷的是, 您可以使用与构建流程引擎时相同的方法来动态注册(和删除)新的租户 。 Activiti引擎将确保已创建或验证数据库架构。

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

这是一部电影,显示正在运行的单元测试以及有效隔离的数据:

多租户工作执行者

最后一个难题是工作执行者。 常规Activiti API调用“借用”当前线程以执行其操作,因此可以使用之前在该线程上设置的任何用户/租户上下文。

但是,作业执行程序使用后台线程池运行,并且没有此类上下文。 由于Activiti中的AsyncExecutor是一个接口,因此实现多方案多租户作业执行器并不难。 当前,我们添加了两个实现。 第一个实现称为SharedExecutorServiceAsyncExecutor

config.setAsyncExecutorEnabled(true);
config.setAsyncExecutorActivate(true);
config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(tenantInfoHolder));

此实现(顾名思义)对所有租户使用一个线程池。 每个租户确实都有其自己的作业获取线程,但是一旦获取了作业,便将其放到共享线程池中。 该系统的好处是Activiti使用的线程数受到限制。

第二种实现称为ExecutorPerTenantAsyncExecutor

config.setAsyncExecutorEnabled(true);
config.setAsyncExecutorActivate(true);
config.setAsyncExecutor(new ExecutorPerTenantAsyncExecutor(tenantInfoHolder));

顾名思义,该类充当“代理” AsyncExecutor。 对于每个注册的租户,将启动完整的默认AsyncExecutor。 每个都有自己的获取线程和执行线程池。 “代理”仅委托给正确的AsyncExecutor实例。 这种方法的好处是,每个租户都可以根据租户的需求进行细粒度的作业执行者配置。

结论

一如既往,欢迎所有反馈。 放手多方案多租户,让我们知道您的想法以及将来可以改进的地方!

翻译自: https://www.javacodegeeks.com/2015/10/multi-tenancy-with-separate-database-schemas-in-activiti.html

activiti 多租户

activiti 多租户_Activiti中具有独立数据库架构的多租户相关推荐

  1. Activiti中具有单独数据库模式的多租户

    我们过去听到的一项功能请求是以多租户方式运行Activiti引擎,使租户的数据与其他租户的数据隔离. 当然,在某些云/ SaaS环境中,这是必须的. 几个月前,波恩大学的学生拉斐尔·吉伦(Raphae ...

  2. activiti脚本任务_Activiti中的安全脚本如何工作

    activiti脚本任务 最近的Activiti 5.21.0版本的突出特点之一是"安全脚本". Activiti用户指南中详细介绍了启用和使用此功能的方法 . 在这篇文章中,我将 ...

  3. activiti脚本任务_Activiti中的高级脚本:自定义配置注入

    activiti脚本任务 脚本任务可能是Activiti代码库中"最古老的"类之一,但是我认为它仍然未被许多人使用. (感知到的)缺点当然是性能(解释还是编译),并且从IDE角度来 ...

  4. “宇宙第一大行”之 MySQL 数据库架构解密

    点击▲关注 "中生代技术"   给公众号标星置顶 更多精彩技术内容 第一时间直达 摘要:本文根据 DTCC 数据库大会分享内容整理而成,将介绍工行 IT 架构转型中传统 OLTP ...

  5. 工商银行 MySQL 数据库架构解密

    摘要:本文根据 DTCC 数据库大会分享内容整理而成,将介绍工行 IT 架构转型中传统 OLTP 数据库架构面临的挑战和诉求,构建基于 MySQL 分布式企业级解决方案实践历程,包括技术选择.高可用设 ...

  6. 多租户数据库设计方法:独立数据库

    目前基于多租户的数据库设计方案通常有如下三种: 独立数据库 共享数据库.独立 Schema 共享数据库.共享数据表 独立数据库 独立数据库:每个租户一个数据库. 优点:为不同的租户提供独立的数据库,有 ...

  7. 云和恩墨zData多租户整合,青海移动数据库云化起航

    『截止到2017年,将会有超过80%的企业会采纳混合云模式部署 ,大幅推动组织变革和业务创新』,这是来自IDC 2016年对于云领域未来的预测. 2017来了,而且毋庸置疑,世界正以势不可挡的趋势朝着 ...

  8. 58 Node.js中操作mongoDB数据库

    技术交流 QQ 群:1027579432,欢迎你的加入! 欢迎关注我的微信公众号:CurryCoder 的程序人生 1.数据库概述及环境搭建 1.1 为什么要使用数据库 动态网站中的数据都是存储在数据 ...

  9. Java嵌入式数据库H2学习总结(三)——在Web应用中嵌入H2数据库

    H2作为一个嵌入型的数据库,它最大的好处就是可以嵌入到我们的Web应用中,和我们的Web应用绑定在一起,成为我们Web应用的一部分.下面来演示一下如何将H2数据库嵌入到我们的Web应用中. 一.搭建测 ...

最新文章

  1. json.net使用说明一
  2. matlab pause
  3. python现在最新的版本-Python 3.8 已发布,现在是切换至新版本的好时机吗?
  4. Spring Boot文档地址
  5. mysql的复杂查询_mysql复杂查询
  6. 华为鸿蒙系统5G有什么联系,【手机|站在5G时代的路口,鸿蒙将带给我们什么?】路口|华为|鸿蒙|其他|系统|硬件_科技资讯_联盟·玩科技...
  7. linux off_t类型的头文件,linux下32位机与64位机基本数据类型长度对比
  8. kaggle房价预测最热解析
  9. 【深度学习系列】卷积神经网络详解(二)——自己手写一个卷积神经网络
  10. SQL Server修改数据
  11. 罗马数字转换python_Python简单实现阿拉伯数字和罗马数字的互相转换
  12. Mac上挂载移动硬盘出现“Read-only file system“问题
  13. html表格可以包含多个tbody,使用Ajax呈现具有多个tbody元素的HTML表格
  14. 作业python 内部小卖铺
  15. manjaro双屏显示
  16. sql中on和where的区别在哪
  17. Java通过openOffice实现word,excel,ppt转成pdf实现在线预览
  18. 3d编辑器的gizmo的缩放计算
  19. 懒人精灵飞桨插件的使用
  20. KDJB-702继保综合检测试验仪

热门文章

  1. P3235-[HNOI2014]江南乐【整除分块,SG函数】
  2. [2020.11.3NOIP模拟赛]选数字【容斥】
  3. jzoj4282-[NOIP2015模拟10.29B组]平方数游戏【构造】
  4. 欢乐纪中A组赛【2019.8.18】
  5. nssl1231-Gift【01背包,dp】
  6. 【模拟】表达式求值(jzoj 1768)
  7. GYM101933I - Intergalactic Bidding
  8. 线段树-楼房重建-洛谷-P4198
  9. 学习分布式不得不会的ACP理论
  10. mysql语句性能开销检测profiling详解