你的位置:首页 > ASP.net教程

[ASP.net教程][Architect] ABP(现代ASP.NET样板开发框架) 多租户


本节目录

  • 什么是多租户
    • 多部署-多数据库
    • 单部署-多数据库
    • 单部署-单数据库
  • 在ABP中的多租户
    • 启用多租户
    • Host vs Tenant
    • Session
    • Data Filters
      • IMustHaveTenant
      • IMayHaveTenant
    • 保存实体

 

什么是多租户

维基百科:软件多租户是1个软件架构,软件的1个实例跑在服务器上,并且为多个租户服务着.

1个租户是指软件中的公用1种特定权限的一群用户.

在多租户的架构下,软件可以为每个租户提供独立的数据,配置,用户管理.

与多实例架构相比,为通过分离软件实例提供给不同租户的操作.

多租户用于创建SaaS(Software as-a Service)应用(云计算).

 

有以下几种多租户:

多部署-多数据库

事实上,这不是多租户.如果我们在单台服务器上提供多租户服务,通过分离数据库,为每个租户提供1个软件实例.我们只需确保多个软件实例在同1个服务器中互不冲突.

已存在的应用几乎都能实现.很容易创建这样的应用,应用不需要关心多租户.

但是他们部署,使用和维护都是问题.

 

单部署-多数据库

在这种情况下,我们可以在服务器上运行1个软件的实例.每个用户登录的时候,我们从master数据库中检查用户的租户,然后获取对应的租户所在数据库信息(连接字符串).

然后我们存储连接字符串到session中,执行数据库操作的时候使用这个特定的连接字符串.

在这个情况下,软件需要设计成多租户的.对于多租户来说,软件大部分是独立的.

同样这种软件也存在安装,使用和部署的问题.我们需要为每个租户创建和部署数据库.

 

单部署-单数据库

这是最真实的多租户架构:我们部署软件的单个实例,部署单个数据库到一台服务器上.

我们会在需要做多租户的表中设计1个TenantId 字段.

 

这是容易部署和维护的.但是创建这样的软件比较难.

因为,我们需要阻止1个租户去读写其他租户的数据.我们为每次数据读操作可能需要添加1个TenantId filter.

同样的,如果这个实体和当前租户关联.我们在每次写的时候需要检查.这是非常无趣且容易出错的.

但是ABP会使用自动数据过滤帮助我们处理这些.

 

如果我们有多租户的大量数据,这种方法可能会有性能问题.我们可以分表或者为1组租户提供不同服务器.

在ABP中的多租户

ABP 提供了1个创建单部署,单数据库,多租户的架构框架支持.

 

启用多租户

多租户默认是禁用的.我们可以在PreInitialize 中启用.如下:

Configuration.MultiTenancy.IsEnabled = true; 

  

Host vs Tenant

首先,我们说明多租户的2个条目.

  • 租户:1个客户有他自己的用户,角色,权限,设置...以及完全独立其他租户使用这个软件.如果是1个CRM软件,不同的租户有他们自己的账户,联系人,产品和订单.所以,当我们说'多租户用户',我们指的是属于1个租户的用户.
  • 租主:租主是唯一的.租主可以创建和管理租户.所以,一个'租主用户'是1个更高级别的,独立所有租户和管理他们.

 

Session

ABP定义了1个获取当前用户和租户的接口IAbpSession .这个接口在多租户下可以获取当前租户id.他会通过id过来数据.

  • 如果UserId and TenantId都为null,当前用户未登录.所以,我们不知道当前用户角色.这种情况下,不会授权操作.
  • 如果UserId is not null and TenantId is null,我们认为当前用户为host user.
  • 如果UserId is not null and also TenantId is not null,我们认为当前用户tenant user.

(See session documentation for more information on the session.)

 

Data Filters

当从数据中查询实体,我们必须添加TenantId 获取当前tenant的数据.当你的实体,实现2个接口其中之一的时候,ABP会自动实现.(IMustHaveTenant and IMayHaveTenant)

 
IMustHaveTenant

这个接口通过TenantId 属性定义不同租户.

public class Product : Entity, IMustHaveTenant{  public int TenantId { get; set; }      public string Name { get; set; }    //...other properties}

这样,ABP就知道这是1个租户实体,会自动过滤tenant.

IMayHaveTenant 

当我们需要在host和tenants共享实体时.即这个实体可能属于tenant或者是host.IMayHaveTenant 接口可以定义1个可空的TenantId.

public class Role : Entity, IMayHaveTenant{  public int? TenantId { get; set; }      public string RoleName { get; set; }    //...other properties}

  

以上例子中,我们用同1个Role类存储Host roles and Tenant roles.当TenantId 属性为null时,表示为host entity,不为null,表示这个实体属于指定的tenant.

IMayHaveTenant 不像IMustHaveTenant常用.比如:Product 类不能实现IMayHaveTenant 接口,当Product 类和实际软件需要相关,和tenants不不相关.

使用IMayHaveTenant 接口在host和tenant中共享,会更难维护代码.

保存实体

1个租户用户无法创建和修改其他租户实体.

只要data filters开启,ABP会在保存数据前检查确认.(See data filters document for more information on data filters.)