日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

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

發(fā)布時(shí)間:2023/12/3 数据库 67 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Activiti中具有单独数据库模式的多租户 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我們過(guò)去聽(tīng)到的一項(xiàng)功能請(qǐng)求是以多租戶方式運(yùn)行Activiti引擎,使租戶的數(shù)據(jù)與其他租戶的數(shù)據(jù)隔離。 當(dāng)然,在某些云/ SaaS環(huán)境中,這是必須的。

幾個(gè)月前,波恩大學(xué)的學(xué)生拉斐爾·吉倫(Raphael Gielen)與我接觸,他正在撰寫(xiě)有關(guān)Activiti中多租戶的碩士論文。 幾周前,我們?cè)谝粋€(gè)共同工作的咖啡館聚會(huì),反彈想法,并為租戶一起破解了具有數(shù)據(jù)庫(kù)模式隔離的第一個(gè)原型。 很有趣 :-)。

無(wú)論如何,我們一直在完善和完善該代碼,并將其提交給Activiti代碼庫(kù)。 讓我們?cè)谙旅娴那皟蓚€(gè)部分中了解使用Activiti進(jìn)行多租戶的現(xiàn)有方法。 在第三部分中,我們將深入研究新的多租戶多模式功能,其中包含一些實(shí)際工作的代碼示例!

共享數(shù)據(jù)庫(kù)多租戶

Activiti已經(jīng)有多租戶功能了一段時(shí)間(自版本5.15起)。 所采用的方法是共享數(shù)據(jù)庫(kù) :擁有一個(gè)(或多個(gè))Activiti引擎,并且它們都進(jìn)入同一個(gè)數(shù)據(jù)庫(kù)。 數(shù)據(jù)庫(kù)表中的每個(gè)條目都有一個(gè)租戶標(biāo)識(shí)符 ,最好將其理解為該數(shù)據(jù)的一種標(biāo)記。 然后,Activiti引擎和API會(huì)讀取并使用該租戶標(biāo)識(shí)符在租戶的上下文中執(zhí)行其各種操作。

例如,如下圖所示,兩個(gè)不同的租戶可以具有使用相同密鑰的流程定義。 引擎和API確保沒(méi)有數(shù)據(jù)混合。

這種方法的好處是部署簡(jiǎn)單,因?yàn)榕c設(shè)置“常規(guī)” Activiti引擎沒(méi)有區(qū)別。 缺點(diǎn)是您必須記住使用正確的API調(diào)用(即那些考慮了租戶標(biāo)識(shí)符的調(diào)用)。 而且,它與任何具有共享資源的系統(tǒng)都存在相同的問(wèn)題:租戶之間總是存在對(duì)資源的競(jìng)爭(zhēng)。 在大多數(shù)用例中,這很好,但是有些用例不能以這種方式完成,例如為某些租戶提供更多或更少的系統(tǒng)資源。

多引擎多租戶

自Activiti的第一個(gè)版本以來(lái),另一種可能的方法是為每個(gè)租戶簡(jiǎn)單地?fù)碛幸粋€(gè)引擎實(shí)例:

在此設(shè)置中,每個(gè)租戶可以具有不同的資源配置,甚至可以在不同的物理服務(wù)器上運(yùn)行。 當(dāng)然,此圖中的每個(gè)引擎可以是多個(gè)引擎,以提高性能/故障轉(zhuǎn)移/等等。 現(xiàn)在的好處是,資源是為租戶量身定制的。 缺點(diǎn)是設(shè)置比較復(fù)雜(多個(gè)數(shù)據(jù)庫(kù)架構(gòu),每個(gè)租戶都有不同的配置文件,等等)。 每個(gè)引擎實(shí)例都將占用內(nèi)存(但是Activiti會(huì)占用很少的內(nèi)存)。 另外,您無(wú)需編寫(xiě)一些路由組件 ,就可以以某種方式知道當(dāng)前租戶上下文并路由到正確的引擎。

多架構(gòu)多租戶

Activiti多租戶故事的最新添加是在兩周前添加的(這是commit ),同時(shí)是版本5和6的添加。這里,每個(gè)租戶都有一個(gè)數(shù)據(jù)庫(kù)(模式),但只有一個(gè)引擎實(shí)例。 再次,在實(shí)踐中,可能有多個(gè)用于性能/故障轉(zhuǎn)移/實(shí)例的實(shí)例,但是概念是相同的:

好處顯而易見(jiàn):只有一個(gè)引擎實(shí)例可以管理和配置,而且API與非多租戶引擎完全相同。 但最重要的是,租戶的數(shù)據(jù)與其他租戶的數(shù)據(jù)完全分開(kāi)。 缺點(diǎn)(類似于多引擎多租戶方法)是有人需要管理和配置不同的數(shù)據(jù)庫(kù)。 但是復(fù)雜的引擎管理已不復(fù)存在。

我上面鏈接到的提交還包含一個(gè)單元測(cè)試 ,該測(cè)試顯示了多模式多租戶引擎的工作方式。

構(gòu)建流程引擎很容易,因?yàn)橛幸粋€(gè)MultiSchemaMultiTenantProcessEngineConfiguration可抽象出大多數(shù)細(xì)節(jié):

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

這看起來(lái)與啟動(dòng)常規(guī)Activiti流程引擎實(shí)例非常相似。 主要區(qū)別在于我們是使用引擎注冊(cè)租戶。 每個(gè)租戶都需要添加其唯一的租戶標(biāo)識(shí)符和數(shù)據(jù)源實(shí)現(xiàn)。 當(dāng)然,數(shù)據(jù)源實(shí)現(xiàn)需要有自己的連接池。 這意味著您可以根據(jù)使用情況有效地為某些租戶提供不同的連接池配置。 Activiti引擎將確保已創(chuàng)建或驗(yàn)證每個(gè)數(shù)據(jù)庫(kù)架構(gòu)都是正確的。

魔術(shù)以使這一切工作是TenantAwareDataSource 。 這是一個(gè)javax.sql.DataSource實(shí)現(xiàn),它根據(jù)當(dāng)前租戶標(biāo)識(shí)符委托給正確的數(shù)據(jù)源。 此類的想法在很大程度上受到Spring的AbstractRoutingDataSource (站在其他開(kāi)源項(xiàng)目的肩膀上!)的影響。

通過(guò)從TenantInfoHolder實(shí)例獲取當(dāng)前的租戶標(biāo)識(shí)符 ,可以路由到正確的數(shù)據(jù)源。 正如您在上面的代碼片段中看到的那樣,在構(gòu)造MultiSchemaMultiTenantProcessEngineConfiguration時(shí),這也是必需的參數(shù)。 TenantInfoHolder是您需要實(shí)現(xiàn)的接口,具體取決于您環(huán)境中用戶和租戶的管理方式。 通常,您將使用ThreadLocal來(lái)存儲(chǔ)由某些安全過(guò)濾器填充的當(dāng)前用戶/租戶信息(類似于Spring Security)。 該類有效地充當(dāng)下圖中的“路由組件”:

在單元測(cè)試示例中,我們確實(shí)使用ThreadLocal來(lái)存儲(chǔ)當(dāng)前的租戶標(biāo)識(shí)符 ,并用一些演示數(shù)據(jù)填充它:

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

現(xiàn)在,我們開(kāi)始一些流程實(shí)例,同時(shí)還要切換當(dāng)前的租戶標(biāo)識(shí)符。 在實(shí)踐中,您必須想象多個(gè)線程隨請(qǐng)求一起進(jìn)入,并且它們將根據(jù)登錄的用戶設(shè)置當(dāng)前的租戶標(biāo)識(shí)符:

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

上面的startProcessInstances方法將使用標(biāo)準(zhǔn)Activiti API設(shè)置當(dāng)前用戶和租戶標(biāo)識(shí)符,并啟動(dòng)幾個(gè)流程實(shí)例, 就好像根本沒(méi)有多租戶一樣 ( completeTasks方法類似地完成了一些任務(wù))。

同樣很酷的是, 您可以通過(guò)使用與構(gòu)建流程引擎時(shí)相同的方法來(lái)動(dòng)態(tài)注冊(cè)(和刪除)新的租戶 。 Activiti引擎將確保已創(chuàng)建或驗(yàn)證數(shù)據(jù)庫(kù)架構(gòu)。

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

這是一部電影,顯示正在運(yùn)行的單元測(cè)試以及有效隔離的數(shù)據(jù):

多租戶執(zhí)行器

最后一個(gè)難題是工作執(zhí)行者。 常規(guī)Activiti API調(diào)用“借用”當(dāng)前線程以執(zhí)行其操作,因此可以使用之前在該線程上設(shè)置的任何用戶/租戶上下文。

但是,作業(yè)執(zhí)行程序使用后臺(tái)線程池運(yùn)行,并且沒(méi)有此類上下文。 由于Activiti中的AsyncExecutor是一個(gè)接口,因此實(shí)現(xiàn)多模式多租戶作業(yè)執(zhí)行器并不難。 當(dāng)前,我們添加了兩個(gè)實(shí)現(xiàn)。 第一個(gè)實(shí)現(xiàn)稱為SharedExecutorServiceAsyncExecutor :

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

此實(shí)現(xiàn)(顧名思義)對(duì)所有租戶使用一個(gè)線程池。 每個(gè)租戶確實(shí)有其自己的作業(yè)獲取線程,但是一旦獲取了作業(yè),便將其放到共享線程池中。 該系統(tǒng)的好處是Activiti使用的線程數(shù)受到限制。

第二種實(shí)現(xiàn)稱為ExecutorPerTenantAsyncExecutor :

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

顧名思義,該類充當(dāng)“代理” AsyncExecutor。 對(duì)于每個(gè)注冊(cè)的租戶,將啟動(dòng)完整的默認(rèn)AsyncExecutor。 每個(gè)都有自己的獲取線程和執(zhí)行線程池。 “代理”僅委托給正確的AsyncExecutor實(shí)例。 這種方法的好處是,每個(gè)租戶都可以根據(jù)租戶的需求進(jìn)行細(xì)粒度的作業(yè)執(zhí)行者配置。

結(jié)論

一如既往,歡迎所有反饋。 放手多方案多租戶,讓我們知道您的想法以及將來(lái)可以改進(jìn)的地方!

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

總結(jié)

以上是生活随笔為你收集整理的Activiti中具有单独数据库模式的多租户的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。