ABP框架 - 多租户
本节内容:
什么是多租户
维基百科:“软件多租户是一个软件架构,软件只有一个实例运行在服务器,并服务于多个租户。一个租户包含一组用户,他们拥有指定权限,共同访问一个软件实例。一个多租户架构,应用程序为每个租户提供一个专属于他们的数据、配置、用户管理、租户特有的功能和属性。多租户架构而多实例框架抽象而成,多实例架构是把每个实例看成一个租户。“
多租户通常用来创建Saas(软件作为服务)应用(云计算)。多租户有多种架构:
多部署 - 多数据库
这种实际上不算多租户,但是,如果我们为每个客户(租户)运行应用的一个实例,并使用一个独立的数据库,那么我们就可以在一台服务器上为多个租户服务,我们只要确保应用的多个实例不要在一个服务器的环境下互相冲突就行。
为一个不是为多租户设计,但已经在运行的应用,提供了可能性。这种方式虽然使得创建一个不考虑多租户的应用相对容易,但在安装、使用和维护方面有些问题。
单部署 - 多数据库
用这种方式,我们在一个服务器上运行应用的单一实例,我们有一个主(宿主)数据库存储租户元数据(像租户名和子域),并为每个租户维护一个隔离的数据库。我们一旦识别当前租户(例如:从子域或从一个用户登录窗体),就切换到该租户的数据库里执行操作。
用这种方式,我们应该在设计应用时,在某些层面上设计成多租户,但应用的大部分还是不依赖于多租户。
我们应该为每个租户创建并维护一个隔离的数据库,包括数据迁移。如果我们有多租户就需要维护它们专有的数据库,在应用更新时,可能就需要花很长的时间进行数据库结构迁移。由于我们有租户的隔离的数据库,所以我们可以单独地备份各自的数据库,同样在租户要求下,我们也可以移动租户数据库到一个更强大的服务器。
单部署 - 单数据库
这是最纯粹的多租户架构:我们只在一台服务器上部署应用的单个实例和单个数据库。我们在每个表(关系型数据库)里用一个TenantId(租户Id或类似的)字段来区分隔离每个租户数据。
这种方式易于安装和维护,但难于创建这种应用,因为我们必须防止一个租户读或写其它租户数据。我们得为每次的数据库读取(select)操作添加TenantId来过滤。同样,我们也在每次写数据库时进行检查当前实体是否与当前租户相关,这就是乏味和易犯错的地方。但ABP自动使用数据过滤技术帮我们解决这些问题。
这种方式在有很多租户和大数据量的情况下,可能带来性能问题,我们可以使用表分区或其它数据库特性来解决这个问题。
单部署 - 混数据库
我们可能想存储租户数据到一个数据库,但想为有需要的租户创建单独的数据库。例如,我们可以存储租户的大数据到各自的数据库,但其它的都保存到另一数据库。
多部署 - 单/多/混 数据库
最后,我们可能想部署我们的应用到多个服务器(像分布式服务器集群)获得更好地性能、实用性和扩展性。这是一种依赖于数据库的方式。
ABP中的多租户
ABP可用于上述所描述的场景。
启用多租户
默认情况多租户是禁用的,我们可以在我们模块的PreInitialize(预初始化)里启用它,如下:
Configuration.MultiTenancy.IsEnabled = true;
宿主与租户
首先我们要在多租户系统里定义两个术语:
- Tenant(租户):一个客户,拥有多个用户、角色、许可、设置等,并要单独地使用这个应用。一个多租户应用可能有多个租户,每个租户有它自己的帐户、联系人、产品及其它。所以当我们说一个“Tenant user(租户用户)”,表示一个租户下的一个用户。
- Host(宿主):宿主是单例的(就一个宿主),这个宿主负责创建和管理租户,所以“Host user(宿主用户)”拥有更高级别,不依赖于租户,并能控制租户。
会话(Session)
ABP定义了IAbpSession接口,用来获取user(用户)和tenant id(租户Id)。该接口在多租户系统中默认情况下获取当前租户Id,因此它能基于租户Id过滤数据。有如下规则:
- 如果用户Id和租户Id都为null,当前用户尚未登录到系统,所以我们不知道它是宿主用户还是租户用户。这种情况下,用户不能访问需要授权的内容。
- 如果用户Id不为null,租户Id为null,我们就可以知道当前用户为宿主用户。
- 如果用户id不为null,租户Id也不为null,我们就可以知道当前用户为租户用户。
查看会话文档获取更多相关信息。
数据过滤
在多租户单数据库方式里,我们必须添加一个TenantId(租户Id)过滤,从数据库中只获取当前租户的实体。当你的实体实现IMustHaveTenant和ImayHaveTenant两个接口中的一个,ABP就会自动做到这点。
IMustHaveTenant 接口
该接口通过定义TenantId属性为不同租户区分实体。如下所示,一个实体实现IMustHaveTenant:
public class Product : Entity, IMustHaveTenant
{
public int TenantId { get; set; } public string Name { get; set; } //...other properties
}
因此ABP知道这是一个特定租户的实体并自动与其它租户的实体分离。
IMayHaveTenant 接口
我们有时需要在宿主与租户之间共享一个实体,所以一个实体可能是宿主的或租户的。IMayHaveTenant接口同样定义了TenantId属性(类似于IMustHaveTenant),但它是nullable(可空的)。如下所示,一个实体实现IMayHaveTenant:
public class Role : Entity, IMayHaveTenant
{
public int? TenantId { get; set; } public string RoleName { get; set; } //...other properties
}
我们可以使用两样的role类来存储宿主角色和租户角色,在这种情况下,靠TenantId属性来区分是宿主实体还是租户实体。如果为null表示这是一个宿主实体,否则它就是一个租户实体,它的值就是租户Id。
补充提醒:
IMayHaveTenant没有IMustHaveTenant那么常用。例如:一个Product(产品)类不能是IMayHaveTenant,因为它跟应用功能切实相关的,而与租户的管理无关。所以在使用IMayHaveTenant接口时要格外小心,毕竟维护共享于宿主与租户的代码比较难。
当你定义一个实体类型为IMustHaveTenant或IMayHaveTenant后,在创建一个新实体时应该特意去设置TenantId(尽管ABP会尝试把当前TenantId赋给它,但某些情况下不会成功,尤其是使用IMayHaveTenant的实体)。大部分情况,这个TenantId属性是唯一需要处理的点,当你写LINQ时,不需要显式地在where条件里写TenantId过滤,因为它会自动地被过滤。
在宿主与租户间切换
在多租户应用数据库上,我们应该知道当前租户,默认情况下,可以从IAbpSession中获取(如之前所述)。但我们可以改变这种行为,切换到其它租户的数据库上,例如:
public class ProductService : ITransientDependency
{
private readonly IRepository<Product> _productRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager; public ProductService(IRepository<Product> productRepository, IUnitOfWorkManager unitOfWorkManager)
{
_productRepository = productRepository;
_unitOfWorkManager = unitOfWorkManager;
} [UnitOfWork]
public virtual List<Product> GetProducts(int tenantId)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return _productRepository.GetAllList();
}
}
}
SetTenantId确保我们工作于给定的租户的数据,获取方式依数据库而定:
- 如果给定的租户有特定的数据库,它切换到这个数据库,从中获取产品。
- 如果给定的租户没有特定的数据库(例如:单数据库方式),它自动添加TenantId过滤到查询里,只获取给定租户的产品。
如果我们不使用SetTenantId,如前面所说,将从会话中获取TenantId。这里有些提醒和最佳实践:
- 使用SetTenantId(null)可切换到宿主。
- 如果没有特殊情况,要像示例那样,在using块里使用SetTenantId,因为它会在块后面自动还原TenantId的值,并且调用GetProducts方法的代码也会像调用前那样工作。
- 如果有需要,你可以块里嵌套使用SetTenantId
- 由于_unitOfWorkManger.Current仅在同一工作单元内可用,所以确保你的代码是运行在同一个工作单元内。
ABP框架 - 多租户的更多相关文章
- X-Admin&ABP框架开发-租户管理
软件即服务概念的推动,定制化到通用化的发展,用一套代码完成适应不同企业的需求,利用多租户技术可以去做到这一点.ABP里提供了多租户这一概念并且也在Zero模块中实现了这一概念. 一.多租户的概念 单部 ...
- 详解ABP框架的多租户
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下 ...
- ABP框架系列之三十四:(Multi-Tenancy-多租户)
What Is Multi Tenancy? "Software Multitenancy refers to a software architecture in which a sing ...
- ABP框架 - 功能管理
文档目录 本节内容: 简介 关于 IFeatureValueStore 功能类型 Boolean 功能 Value 功能 定义功能 基本功能属性 其它功能属性 功能层次 检查功能 使用Requires ...
- ABP框架详解(四)Feature
ABP框架中存在一个Feature的特性,功能和设计思路非常类似于框架中的Authorization功能,都是来控制用户是否能够继续操作某项功能,不同点在于Authorization默认是应用在IAp ...
- ABP框架详解(三)Domain
此处的Domain主要指Abp类库根目录下Domain文件夹.顾名思义该目录下是用来存放与领域实体,领域逻辑执行,存储,领域服务相关的内容. 1.Entities (1)为整个Abp框架后期开发的所有 ...
- ABP框架详解(二)AbpKernelModule
AbpKernelModule类是Abp框架自己的Module,它也跟所有其他的Module一样继承自AbpModule,重写PreInitialize,Initialize,PostInitiali ...
- ABP框架个人开发实战(1)_环境搭建
前言 之前关注ABP框架有一阵子了,一直没有潜下心来实际研究一下.最近想自己建站,以后有自己的功能开发项目,可以在自己的站点上开发,并一步步的完善,所以找个比较好用的框架迫在眉睫,选来选去,决定用AB ...
- ABP框架记录
1.先在Core项目中建立模型Models>Model.cs/ModelManager.cs 2.在Application中建立接口和具体类:IModelAppService.csModelAp ...
随机推荐
- 【.net 深呼吸】细说CodeDom(5):类型成员
前文中,老周已经厚着脸皮介绍了类型的声明,类型里面包含的自然就是类型成员了,故,顺着这个思路,今天咱们就了解一下如何向类型添加成员. 咱们都知道,常见的类型成员,比如字段.属性.方法.事件.表示代码成 ...
- 消息队列——RabbitMQ学习笔记
消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...
- boosting、adaboost
1.boosting Boosting方法是一种用来提高弱分类算法准确度的方法,这种方法通过构造一个预测函数系列,然后以一定的方式将他们组合成一个预测函数.他是一种框架算法,主要是通过对样本集的操作获 ...
- UITextView 输入字数限制
本文介绍了UITextView对中英文还有iOS自带表情输入的字数限制,由于中文输入会有联想导致字数限制不准确所以苦恼好久,所以参考一些大神的博客终于搞定,欢迎大家参考和指正. 对于限制UITextV ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- [版本控制之道] Git 常用的命令总结(欢迎收藏备用)
坚持每天学习,坚持每天复习,技术永远学不完,自己永远要前进 总结日常开发生产中常用的Git版本控制命令 ------------------------------main-------------- ...
- ASP.NET Core的路由[2]:路由系统的核心对象——Router
ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...
- gitHub使用入门和github for windows的安装教程
在看这篇教程之前我想大家也在搜索怎样使用gitHub托管自己的项目,在使用gitHub之前我也遇到过各种问题,在网上我也搜索了很多,但总觉得网上搜索到的东西很多很杂,有的根本不知道是在表达什么.在这过 ...
- potrace源码分析一
1 简介 potrace是由Dalhousie University的Peter Selinger开发一款位图轮廓矢量化软件,该软件源码是可以公开下载的,详细见项目主页:http://potrace. ...
- AI人工智能系列随笔:syntaxnet 初探(1)
人工智能是 最近的一个比较火的名词,相信大家对于阿尔法狗都不陌生吧?其实我对人工智能以前也是非常抵触的,因为我认为机器人会取代人类,成为地球乃至宇宙的霸主,但是人工智能带给我的这种冲击,我个人感觉是欲 ...