自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我對實現(xiàn)多租戶系統(tǒng)的一點思考

開發(fā) 項目管理
目前大部分的企業(yè)信息化都是私有化部署,局限于企業(yè)的內(nèi)部網(wǎng)絡(luò),無法實現(xiàn)遠程協(xié)同辦公,所以越來越多的 To B 企業(yè)逐步轉(zhuǎn)向 SaaS(Software-as-a-Service,軟件即服務(wù)),SaaS 最早是美國Salesforce公司(1999年創(chuàng)立)創(chuàng)造的新軟件服務(wù)模式。

[[399862]]

本文轉(zhuǎn)載自微信公眾號「不止dotNET」,作者不止dotNET。轉(zhuǎn)載本文請聯(lián)系不止dotNET公眾號。

2020年突發(fā)的新冠疫情,讓在線協(xié)同辦公在疫情期間成為了剛需。我們也從 2020 年的 2月3 日開始在家遠程辦公,直到四月份。協(xié)同辦公軟件一下子火爆了起來,釘釘、企業(yè)微信、特別是騰訊會議等都在疫情期間表現(xiàn)突出,呈現(xiàn)出井噴式的發(fā)展。

目前大部分的企業(yè)信息化都是私有化部署,局限于企業(yè)的內(nèi)部網(wǎng)絡(luò),無法實現(xiàn)遠程協(xié)同辦公,所以越來越多的 To B 企業(yè)逐步轉(zhuǎn)向 SaaS(Software-as-a-Service,軟件即服務(wù)),SaaS 最早是美國Salesforce公司(1999年創(chuàng)立)創(chuàng)造的新軟件服務(wù)模式。這家公司的市值在 2019 年已經(jīng)超過1000億美元,國內(nèi)現(xiàn)在還處在發(fā)展中階段,前景還是十分廣闊的。

要將傳統(tǒng)的私有化部署的軟件重構(gòu)成支持 SaaS 模式,多租戶是一個邁不過去的坎,首先需要將系統(tǒng)改造成多租戶模式,然后再逐步實現(xiàn)計費、系統(tǒng)監(jiān)控、用戶行為分析等功能。

我覺得多租戶的設(shè)計應(yīng)該分為三個層面來進行討論,應(yīng)用、數(shù)據(jù)庫和中間件。

應(yīng)用

現(xiàn)在的項目或產(chǎn)品開發(fā)幾乎都是前后端分離的開發(fā)模式,應(yīng)用層主要指的是 WebAPI ,WebAPI 的改造有兩種方式:

1、每個租戶部署一套 WebAPI、上層通過域名或 Url 地址的解析進行路由,當(dāng)有新租戶注冊的時候就動態(tài)進行對應(yīng)的 WebAPI 的部署,這種方式改造成本低,但運維成本高,不建議使用,如果時間緊,可以當(dāng)過度階段的臨時方案。

2、所有的租戶共用一套 WebAPI ,在 WebAPI 中需要獲取到租戶信息(域名、Url參數(shù)、請求頭信息、Cookie 等),然后進行租戶信息配置的切換。有新租戶創(chuàng)建的時候無需進行新的 WebAPI 的創(chuàng)建,只需要初始化租戶基本信息即可。

在這種方式下,如果 Cluster1 的負載超過限度了,也要能夠進行動態(tài)切換,將其中的某些租戶切換到其他的 Cluester 中,如上圖。

在 WebAPI 的代碼實現(xiàn)上,可以參考 Abp 框架中多租戶的實現(xiàn),這里給出一個簡化版本:

TenantConfiguration:租戶配置信息

  1. [Serializable
  2. public class TenantConfiguration 
  3.     public Guid Id { get; set; } 
  4.  
  5.     public string Code { get; set; } 
  6.  
  7.     public string Name { get; set; } 
  8.  
  9.     public TenantStatus TenantStatus { get; set; } 
  10.  
  11.     public string DBConfig { get; set; } 
  12.  
  13.     public string CacheConfig { get; set; } 
  14.  
  15.     public string MQConfig { get; set; } 
  16.  
  17.     public string MongoConfig { get; set; } 
  18.  
  19.     public TenantConfiguration() 
  20.     { 
  21.         TenantStatus = TenantStatus.Enable; 
  22.     } 
  23.  
  24.     public TenantConfiguration(Guid id, string name
  25.         : this() 
  26.     { 
  27.         
  28.         Id = id; 
  29.         Name = name
  30.     } 

TenantStore:從緩存或數(shù)據(jù)庫中獲取租戶配置信息

  1. public interface ITenantStore 
  2.     TenantConfiguration Find(string code); 
  3. public class TenantStore : ITenantStore 
  4.     public TenantConfiguration Find(string code) 
  5.     { 
  6.         //從緩存或數(shù)據(jù)庫進行租戶配置信息獲取 
  7.         throw new NotImplementedException(); 
  8.     } 

CurrentTenant:當(dāng)前租戶類,用來存儲當(dāng)前租戶信息,以及切換租戶

  1. public interface ICurrentTenant 
  2.  
  3.     TenantConfiguration Config { get;} 
  4.     IDisposable Change(string code); 
  5. /// <summary> 
  6. /// 當(dāng)前租戶 
  7. /// </summary> 
  8. public class CurrentTenant:ICurrentTenant 
  9.     public ITenantStore _tenantStore; 
  10.     public CurrentTenant(ITenantStore tenantStore) 
  11.     { 
  12.         _tenantStore = tenantStore; 
  13.     } 
  14.  
  15.     public TenantConfiguration _config; 
  16.     public TenantConfiguration Config => _config; 
  17.  
  18.     /// <summary> 
  19.     /// 切換租戶 
  20.     /// </summary> 
  21.     /// <param name="code"></param> 
  22.     /// <returns></returns
  23.     public IDisposable Change(string code) 
  24.     { 
  25.         TenantConfiguration tenantConfig= _tenantStore.Find(code); 
  26.         if (tenantConfig == null
  27.         { 
  28.             throw new Exception("Tenant not found"); 
  29.         } 
  30.  
  31.         if (tenantConfig.TenantStatus != TenantStatus.Enable) 
  32.         { 
  33.             throw new Exception("Tenant is disabled or deleted"); 
  34.         } 
  35.  
  36.         return new DisposeAction(() => 
  37.         { 
  38.             _config = tenantConfig; 
  39.         }); 
  40.     } 

UrlTenantResolve:根據(jù) Url 參數(shù)進行租戶解析

  1. public interface ITenantResolve 
  2.     string Resolve(HttpContext httpContext); 
  3. /// <summary> 
  4. ///  
  5. /// </summary> 
  6. public class UrlTenantResolve:ITenantResolve 
  7.  
  8.     public string Resolve(HttpContext httpContext) 
  9.     { 
  10.         return httpContext.Request.QueryString.HasValue 
  11.            ? httpContext.Request.Query["__tenant"].ToString() 
  12.            : null
  13.     } 

MultiTenancyMiddleware:租戶中間件,關(guān)于在 dotNET Core 中自定義中間件可以參考《dotNET Core 3.X 請求處理管道和中間件的理解》

  1. public class MultiTenancyMiddleware: IMiddleware 
  2.     protected readonly ITenantResolve _tenantResolve; 
  3.     private readonly ICurrentTenant _currentTenant; 
  4.  
  5.     public MultiTenancyMiddleware( 
  6.        ITenantResolve tenantResolve, 
  7.        ICurrentTenant currentTenant) 
  8.     { 
  9.         _tenantResolve = tenantResolve; 
  10.         _currentTenant = currentTenant; 
  11.     } 
  12.  
  13.     public async Task InvokeAsync(HttpContext context, RequestDelegate next
  14.     { 
  15.         var tenantCode = _tenantResolve.Resolve(context); 
  16.  
  17.         if (tenantCode != _currentTenant.Config.Code) 
  18.         { 
  19.             using (_currentTenant.Change(tenantCode)) 
  20.             { 
  21.                 await next(context); 
  22.             } 
  23.         } 
  24.         else 
  25.         { 
  26.             await next(context); 
  27.         } 
  28.  
  29.         await next(context); 
  30.     } 

數(shù)據(jù)庫

數(shù)據(jù)庫在這里指的是關(guān)系型數(shù)據(jù)庫,用來存儲業(yè)務(wù)數(shù)據(jù),實現(xiàn)多租戶,就要對數(shù)據(jù)進行隔離,通常的數(shù)據(jù)隔離方式有三種模式:

1、完全隔離,每個租戶使用獨立數(shù)據(jù)庫;

2、部分共享,租戶共享一個數(shù)據(jù)庫,以 schema 或者 table 區(qū)分;

3、完全共享,租戶共享相同的數(shù)據(jù)庫表,以 tenant_id 進行區(qū)分

推薦使用第一種或第二種,隔離程度比較高,也比較容易做橫向擴展,如果是第三種,需要處理數(shù)據(jù)的隔離問題,需要處理單表大數(shù)據(jù)的問題等,對技術(shù)要求比較高。

中間件

除了數(shù)據(jù)庫,一個系統(tǒng)還需要依賴其他的一些中間件,比如緩存、消息隊列、文件存儲:

  • 緩存:Redi
  • 消息隊列:RabbitMQ
  • 文件存儲:MongoDB 的 GridFS

Redis

1、Redis 中使用數(shù)據(jù)庫的方式進行租戶隔離;

2、Redis 可以通過修改配置文件的方式進行數(shù)據(jù)庫的擴展,默認為 16 個;3、通過 Redis 分片集群的方式進行部署,可以進行橫向擴展;3、在 Redis 集群中,官方推薦節(jié)點數(shù)量不超過 1000 個,這個對于多租戶系統(tǒng)的前期來說應(yīng)該是夠用了,如果到了租戶數(shù)量的爆發(fā)期,再進行架構(gòu)的擴展,比如,不同的租戶路由到不同的 Redis 集群中。

RabbitMQ

在 Rabbitmq 有 vhost 機制,可以一個租戶創(chuàng)建一個vhost,通過 vhost 來進行租戶的隔離,目前還沒查詢到 vhost 是否有上限,需要做進一步驗證。

MongoDB

MongoDB 中主要使用 GridFS 來進行非結(jié)構(gòu)化數(shù)據(jù)的存儲,通過創(chuàng)建數(shù)據(jù)庫的方式來進行租戶的隔離,而且 MongoDB 支持分片的集群部署方式,可以進行擴展橫擴展,在前期,一個 MongoDB 集群應(yīng)該就夠用了。

最后

技術(shù)方案和架構(gòu)沒有最好的,只有最適合的,符合當(dāng)下的業(yè)務(wù)場景、團隊的技術(shù)能力就可以,然后要做的就是做 MVP (最小可行性產(chǎn)品),進而進行系統(tǒng)的改造。

希望本文對您有所幫助!

 

責(zé)任編輯:武曉燕 來源: 不止dotNET
相關(guān)推薦

2014-09-17 10:30:25

代碼

2011-07-04 09:33:04

惠普轉(zhuǎn)型李艾科

2022-07-13 08:45:29

云原生容器網(wǎng)絡(luò)

2014-09-23 11:21:05

代碼命名程序員架構(gòu)設(shè)計

2011-12-23 09:16:19

2013-05-14 12:06:26

.Net系統(tǒng)架構(gòu)架構(gòu)設(shè)計

2013-05-13 11:25:44

系統(tǒng)架構(gòu)

2019-03-22 14:38:03

容器安全隔離

2013-03-06 10:19:56

重構(gòu)架構(gòu)設(shè)計

2011-07-18 16:33:20

sqlite

2013-06-26 10:13:32

C語言結(jié)構(gòu)體結(jié)構(gòu)體偏移

2022-04-06 07:14:29

區(qū)塊鏈網(wǎng)絡(luò)生態(tài)系統(tǒng)

2014-07-24 13:32:01

Google NowSiri

2015-03-26 09:23:17

天璣科技融合架構(gòu)

2014-11-25 11:52:15

.NET

2021-05-20 09:11:00

5G5G網(wǎng)絡(luò)5G終端

2023-04-11 14:42:14

2023-06-07 13:50:00

SaaS多租戶系統(tǒng)

2021-09-28 18:54:26

信息流大數(shù)據(jù)人工智能

2015-11-02 09:43:25

ASP.NET異步編程
點贊
收藏

51CTO技術(shù)棧公眾號