返回总目录


本篇目录

什么是多租户###

维基百科:“软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务”。一个租户是一组共享该软件实例特定权限的用户。有了多租户架构,软件应用被设计成为每个租户提供一个 专用的实例包括该实例的数据的共享,还可以共享配置,用户管理,租户自己的功能和非功能属性。多租户和多实例架构相比,多租户分离了代表不同的租户操作的多个实例。

多租户用于创建Saas(Software as-a service)应用(云处理)。有几种类型的多租户:

多部署-多数据库

这实际上不是多租户。但是,如果我们为每个具有分开数据库的客户(租户)运行该应用的一个实例,那么我们可以在单个服务器上为多个租户提供服务。我们可以确定该应用的多个实例在相同的服务器环境不会相互冲突

这个对于一个不是为多租户设计的已存在应用也是可能的。创建这么一个应用更容易,因为该应用不需要了解多租户。但这种方式存在安装,使用和维护问题。

单部署-多数据库

在这种情况下,我们可以在一个服务器上运行应用的单个实例。对于每个登录用户,我们从master database中检测该用户的租户,并获得该租户的数据库信息(连接字符串)。然后我们可以将连接字符串存储到像session一样的变量中,同时,使用这个租户特定的连接字符串执行所有的数据库操作。

某种程度上,这样的应用应该设计成多租户。但是大多数的应用都独立于多租户。这种方式也存在一些安装,使用和维护问题。我们应该为每个租户创建并维护一个分离的数据库

单部署-单数据库

这是最真实的多租户架构:我们只将具有单个数据库应用的单个实例部署到单个服务器上。在(RDBMS)每个表中,都存在一个TenantId(或相似)字段,该字段用于分离每个租户之间的数据。

这种方法安装和维护都很简单,但唯独创建这么一个应用很难,因为我们必须要阻止一个租户读取或写入其他租户的数据。我们可以为每个数据库的读取(select)操作添加一个TenantId过滤器。而且,我们可以在每次写入的时候检查一下该实体是否和当前的租户相关。这是乏味而易于出错的,但ABP通过使用自动的数据过滤帮助我们处理这个事情。

如果我们有很多具有大量数据的租户,那么这种方法可能会有性能问题。我们可以使用关系型数据库的表分割特征或者将租户按组分到不同的服务器上。

ABP中的多租户###

ABP提供了创建单部署,单数据库,多租户架构的基础设施。

开启多租户

多租户默认是关闭的。我们可以在模块的PreInitialize方法中开启,如下所示:

Configuration.MultiTenancy.IsEnabled = true;

租主vs租户

首先,我们应该定义多租户系统中的两个条目:

  • 租主(Host):租主是单例的(只有一个租主)。租主会对创建和管理租户负责。因此,一个“租主用户”比所有的租户等级更高,并独立于所有租户,同时还能控制他们。
  • 租户(Tenant):租主的一个客户,具有自己的用户角色,权限,设置等。每个租户都可以完全独立于其他租户使用应用。一个多租户应用会有一个或多个租户。如果是一个CRM应用,那么不同的租户也有它们自己的账户,契约,产品和订单。因此,当我们说“**租户用户”的时候,意思就是一个租户拥有的用户。

Session

ABP定义了一个获取当前用户租户id的IAbpSession接口。该接口用于多租户获取当前的租户id。因此,它可以基于当前的租户id过滤数据。ABP中有以下规则:

  • 如果UserId和TenantId都是null,那么当前的用户没有登录到系统。因此,我们可以不知道当前用户是否是一个租主用户还是一个租户用户。在这种情况下,用户不能访问授权的内容。
  • 如果UserId不是null,TenantId是null,那么当前用户是一个租主用户。
  • 如果UserId不是null,TenantId也不是null,那么当前用户是租户用户。

更多关于session的信息请看后面的Session一节。

数据过滤器

当从数据库中检索实体时,我们必须添加一个TenantId过滤器来只获得当前的租户实体。当你为实体实现了IMustHaveTenant和IMayHaveTenant两个接口之一时,ABP会自动地完成数据过滤。

IMustHaveTenant接口

该接口通过定义TenantId属性来区分不同租户的实体。一个实现了IMustHaveTenant的实体例子如下:

public class Product : Entity, IMustHaveTenant
{
public int TenantId { get; set; } public string Name { get; set; } //...其他属性
}

这样,ABP知道这是一个特定租户的实体,并且会自动地将一个租户的实体从其他实体中分离出来。

IMayHaveTenant接口

我们可能需要在租户和租户之间共享一个实体类型。因此,一个实体可能会被一个租户或租主拥有。IMayHaveTenant接口也定义了TenantId(类似于IMustHaveTenant),但在这种情况下是nullable。实现了IMayHaveTenant的一个实体例子:

public class Role : Entity, IMayHaveTenant
{
public int? TenantId { get; set; } public string RoleName { get; set; } //...其他属性
}

我们可能会使用相同的Role类来存储租主角色和租户角色。这种情况下,TenantId表明这是一个租户实体还是一个租主实体。null值表示这是一个租主实体,非null值表示这被一个租户拥有,该租户的Id是TenantId

IMayHaveTenant不像IMustHaveTenant一样常用。比如,一个Product类可以不实现IMayHaveTenant接口,因为Product和实际的应用功能相关,和管理租户不相干。因此,要小心使用IMayHaveTenant接口,因为它更难维护租户和租主共享的代码。

保存实体

一个租户用户不应该创建或编辑其他租户的实体。如果相关的数据过滤器开启了,那么ABP会检查该实体相对于数据库的改变。

想要获得更多关于数据过滤器的信息,请看后面关于数据过滤器的博客。

ABP理论学习之多租户的更多相关文章

  1. ABP理论学习之Javascript API(理论完结篇)

    返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...

  2. 详解ABP框架的多租户

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下 ...

  3. ABP理论学习之开篇介绍

    返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...

  4. ABP理论学习之Abp Session

    返回总目录 本篇目录 介绍 注入Session 使用Session属性 介绍 当应用程序要求用户登录时,那么应用程序也需要知道当前用户正在执行的操作.虽然ASP.NET本身在展现层提供了Session ...

  5. ABP理论学习之设置管理

    返回总目录 本篇目录 介绍 定义设置 获取设置值 更改设置 关于缓存 介绍 每个应用程序都需要存储一些设置信息,然后在应用程序中的某个地方使用这些设置.ABP提供了健壮的基础设施来存储或检索服务端和客 ...

  6. ABP理论学习之数据过滤器

    返回总目录 本篇目录 介绍 预定义过滤器 关闭过滤器 开启过滤器 设置过滤器参数 定义自定义过滤器 其他ORM 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除 ...

  7. ABP理论学习之授权(Authorization)

    返回总目录 本篇目录 介绍 定义权限 检查权限 使用AbpAuthorize特性 使用IPermissionChecker Razor视图 客户端(Javascript) 权限管理者 介绍 几乎所有的 ...

  8. ABP理论学习之功能管理

    返回总目录 本篇目录 介绍 功能类型 定义功能 检查功能 功能管理者 版本说明 介绍 大多数的Saas(多租户)应用都有不同 功能的 版本(包).因此,他们可以给租户(客户)提供不同的 价格和功能选项 ...

  9. ABP理论学习之审计日志

    返回总目录 本篇目录 介绍 配置 通过特性开启/关闭 注意 我项目中的例子 介绍 维基百科说: "审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,记录集或者记录源,它们提供了活动序 ...

随机推荐

  1. CentOS Linux服务器安全设置

    转自:http://www.osyunwei.com/archives/754.html 引言: 我们必须明白:最小的权限+最少的服务=最大的安全 所以,无论是配置任何服务器,我们都必须把不用的服务关 ...

  2. Android Studio导入第三方类库的方法(转)

    转自:链接 本人也刚刚开始尝试做android app的开发,听说android studio是Google支持的android 应用开发工具,所以想应该肯定比Eclipse好用吧,反正以前没有jav ...

  3. poj上的dp专题

    更新中... http://poj.org/problem?id=1037 dp[i][j][0]表示序列长度为i,以j开始并且前两位下降的合法序列数目; dp[i][j][1]表示序列长度为i, 以 ...

  4. ecplise + hadoop 调试环境搭建

    1.需要安装包 1.1 hadoop源码包(hadoop-2.5.2-src.tar.gz) 1.2 hadoop 2X插件(hadoop2x-eclipse-plugin-master.zip) 1 ...

  5. CollectionView水平和竖直瀑布流的实现

    最近在项目中需要实现一个水平的瀑布流(即每个Cell的高度是固定的,但是长度是不固定的),因为需要重写系统 UICollectionViewLayout中的一些方法通过计算去实现手动布局,所以本着代码 ...

  6. Java实现操作dos命令

    java实现操作dos命令的两种方式 1.读取文件中的命令 package com; import java.io.InputStream; public class cmd { public sta ...

  7. ASP.NET 一句代码实现批量数据绑定

    摘要:对于一个以数据处理为主的应用中的UI层,我们往往需要编写相当多的代码去实现数据绑定.如果界面上的控件和作为数据源的实体类型之间存储某种约定的映射关系,我们就可以实现批量的数据绑定,作者开发了的插 ...

  8. Git小记

    Git简~介 Git是一个分布式版本控制系统,其他的版本控制系统我只用过SVN,但用的时间不长.大家都知道,分布式的好处多多,而且分布式已经包含了集中式的几乎所有功能.Linus创造Git的传奇经历就 ...

  9. Js的typeof和Js的基本数据类型

    本文将从以下几个方面介绍Js的typeof和Js的基本数据类型: ** Js的typeof的用法 ** Js的基本数据类型 ** 使用基本类型使用typeof的返回结果 ** Js的typeof的用法 ...

  10. myeclipse中source not found问题解决办法

    myeclipse中出现source not found是因为你所引用的JavaEE Generic Library没有关联源码,如下图: 下面给出该问题的解决办法: 步骤一:去下载apache-to ...