你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

多租户 SaaS 数据库租户模式

适用于: Azure SQL 数据库

本文介绍可用于多租户 SaaS 应用程序的各种租户模型。

在设计多租户 SaaS 应用程序时,必须慎重选择最符合应用程序需要的租户模型。 租户模型确定如何将每个租户的数据映射到存储。 所选的租户模型会影响应用程序设计和管理。 今后改用不同的模型可能需要付出一定的代价。

A. SaaS 概念和术语

在软件即服务 (SaaS) 模型中,贵公司不会销售软件的许可证。 而是,每个客户都会向贵公司支付租金,使每个客户成为贵公司的租户

作为支付租金的回报,每个租户都可以访问 SaaS 应用程序组件,并将数据存储在 SaaS 系统中。

术语租户模型是指租户存储数据的组织方式:

  • 单租户: 每个数据库仅存储来自一个租户的数据。
  • 多租户: 每个数据库都存储来自多个独立租户的数据(使用保护数据隐私的机制)。
  • 混合租户模式也可用。

B. 如何选择适当的租户模型

一般情况下,租户模型不会影响应用程序的功能,但可能会影响总体解决方案的其他方面。 以下条件用于评估每个模型:

  • 可伸缩性:

    • 租户数目。
    • 每个租户的存储量。
    • 总存储量。
    • 工作负荷。
  • 租户隔离:数据隔离和性能(一个租户的工作负荷是否影响其他租户)。

  • 每个租户的成本: 数据库成本。

  • 开发复杂性:

    • 架构更改。
    • 查询更改(模式所需)。
  • 操作复杂性:

    • 监视和管理性能。
    • 架构管理。
    • 还原租户。
    • 灾难恢复。
  • 可自定义性: 易于支持租户特定或租户类特定的架构自定义。

有关租户的讨论侧重于数据层。 但是,请花费片刻时间思考一下应用程序层。 应用程序层被视为单一实体。 如果将应用程序划分成多个小型组件,所选的租户模型可能会更改。 在所用的租户和存储技术或平台方面,可以不同的方式对待某些组件。

C. 包含单租户数据库的独立单租户应用

应用程序级隔离

在此模型中,针对每个租户重复安装整个应用程序一次。 应用的每个实例是独立实例,因此,它永远不与其他任何独立实例交互。 应用的每个实例只有一个租户,因此只需要一个数据库。 租户包含自身的整个数据库。

设计恰好包含一个单租户数据库的独立应用。

每个应用实例安装在单独的 Azure 资源组中。 软件供应商或租户可以拥有资源组所属的订阅。 在任一情况下,供应商可为租户管理软件。 每个应用程序实例已配置为连接到其相应的数据库。

每个租户数据库都部署为单一数据库。 此模型提供最佳的数据库隔离性。 但是,隔离需要向每个数据库分配足够的资源来处理数据库峰值负载。 此处的一个要点是,无法对不同资源组中部署的数据库或不同的订阅使用弹性池。 从总体数据库成本的角度看,这种限制使得这种独立单租户应用模型成了最昂贵的解决方案。

供应商管理

供应商可以访问所有独立应用实例中的所有数据库,即使应用实例安装在不同的租户订阅中。 访问是通过 SQL 连接实现的。 这种跨实例访问可让供应商出于报告或分析目的,在集中位置进行架构管理和跨数据库查询。 如果需要此类集中化管理,必须部署一个可将租户标识符映射到数据库统一资源标识符 (URI) 的目录。 Azure SQL Database 提供了一个分片库,用于提供目录。 该分片库的正式名称为弹性数据库客户端库

D. 采用“每个租户各有数据库”模型的多租户应用

接下来的这个模式使用包含许多数据库的多租户应用程序,这些数据库都是单租户数据库。 针对每个新租户预配一个新数据库。 可通过为每个节点添加更多的资源来纵向扩展应用程序层。 或者,可通过添加更多的节点来横向扩展应用。 缩放基于工作负荷,不受各个数据库的数目或规模的影响。

设计采用“每个租户各有数据库”模型的多租户应用。

根据租户进行自定义

与独立应用模式一样,使用单租户数据库可提供强大的租户隔离性。 在其模型仅指定了单租户数据库的任何应用中,可以根据任一给定数据库的租户自定义和优化该数据库的架构。 这种自定义不会影响应用中的其他租户。 某个租户所需的数据可能超过了所有租户所需的基本数据字段。 此外,附加的数据字段可能需要索引。

使用“每个租户各有数据库”模型,可以直截了当地定义一个或多个租户的架构。 应用程序供应商必须设计适当的过程,以慎重地大规模管理架构自定义。

弹性池

如果将数据库部署在同一个资源组中,可将其分组到弹性池。 通过池可以经济高效地在许多数据库之间共享资源。 与创建足够大的数据库来适应它所遇到的用量高峰相比,使用这种池选项的成本更低廉。 即使共用数据库共享资源访问权限,也仍能实现较高程度的性能隔离。

使用弹性池设计采用“每个租户各有数据库”模型的多租户应用。

Azure SQL 数据库提供所需的工具用于配置、监视和管理共享。 可在 Azure 门户中查看池级别和数据库级性能指标,也可以通过 Azure Monitor 日志查看。 指标可以提供聚合性能和租户特定性能的深入见解。 可以在池之间移动单个数据库,以便向特定的租户提供保留的资源。 使用这些工具可确保以经济高效的方式获得良好性能。

“每个租户各有数据库”模型的操作规模

Azure SQL 数据库提供多种管理功能,用于大规模管理大量数据库(例如 100,000 以上的数据库)。 这些功能使“每个租户各有数据库”模式变得合理。

例如,假设某个系统使用一个包含 1000 个租户的数据库作为其唯一的数据库。 该数据库可能包含 20 个索引。 如果该系统改用 1,000 个单租户数据库,则索引数量会提高到 20,000 个。 在自动优化过程中,默认会在 Azure SQL 数据库中启用自动索引功能。 自动索引会自动管理所有 20,000 个索引,以及这些索引的持续创建和删除优化操作。 这些自动操作发生在单个数据库内部,不受其他数据库中类似操作的协调或限制。 自动索引在繁忙数据库中处理索引的方式与在不太繁忙的数据库中不同。 如果必须手动完成这种异常繁重的管理任务,则以“每个租户各有数据库”规模进行这种索引管理自定义是不切实际的。

其他可以正常缩放的管理功能包括:

  • 内置备份。
  • 高可用性。
  • 磁盘中加密。
  • 性能遥测。

自动化

可以编写管理操作的脚本,并通过 devops 模型提供这些操作。 甚至可以在应用程序中自动化和公开操作。

例如,可将单个租户自动恢复到以前的某个时间点。 恢复操作只需还原一个存储租户的单租户数据库。 此还原操作不会影响其他租户,确保以每个租户的粒度级完成管理操作。

E. 包含多租户数据库的多租户应用

另一种可用模式是在一个多租户数据库中存储许多租户。 应用程序实例可以包含任意数量的多租户数据库。 多租户数据库的架构必须包含一个或多个租户标识符列,以便能够选择性地检索任意给定租户中的数据。 此外,该架构可能需要几个只由一部分租户使用的表或列。 但是,静态代码和引用数据只会存储一次,并由所有租户共享。

丧失租户隔离性

数据:使用多租户数据库势必会丧失租户隔离性。 多个租户的数据统一存储在一个数据库中。 在开发期间,需确保查询永远不会公开多个租户中的数据。 SQL 数据库支持行级安全性,这种安全性可以强制某个查询返回的数据划归到单个租户。

处理:多租户数据库在其所有租户之间共享计算和存储资源。 可将数据库作为一个整体进行监视,确保其性能可接受。 但是,Azure 系统不提供内置的方式来监视或管理单个租户对这些资源的使用。 因此,多租户数据库增大了遇到干扰性邻居的风险:一个过度活跃的租户的工作负载影响同一数据库中其他租户的性能体验。 更多应用程序级监视可以监视租户级性能。

成本更低

一般而言,多租户数据库的每租户成本最低。 单一数据库的资源成本比同等大小的弹性池的成本更低。 此外,在租户只需有限存储的情况下,有可能会将数百万个租户存储在单个数据库中。 没有任何弹性池可以包含数百万个数据库。 但是,使用包含 1,000 个池、每个池包含 1,000 个数据库的解决方案可以实现百万量级的规模,而风险是管理变得复杂。

下面介绍多租户数据库模型的两种变体,其中,分片多租户模型是灵活性和可伸缩性最高的模型。

F. 包含单个多租户数据库的多租户应用

最简单的多租户数据库模式使用单一数据库来托管所有租户的数据。 添加更多的租户时,该数据库会使用更多的存储和计算资源进行纵向扩展。 通过这种纵向扩展也许能够做到高枕无忧,不过,规模始终有一个最终的限制。 但是,在远远未达到该限制之前,数据库可能就会变得难以管理。

在多租户数据库中,侧重于单个租户的管理操作更难实现。 大规模执行这些操作可能会使速度变得非常缓慢,让人无法接受。 一个例子是只是对一个租户的数据执行时间点还原。

G. 包含分片多租户数据库的多租户应用

大多数 SaaS 应用程序每次只访问一个租户的数据。 使用此访问模式可在多个数据库或分片之间分布租户数据,其中,任一租户的所有数据包含在一个分片中。 将分片模型与多租户数据库模式相结合可以实现几乎无限的规模。

Design of multi-tenant app with sharded multi-tenant databases.

管理分片

分片增大了设计和操作管理的复杂性。 需要在目录中维护租户与数据库之间的映射。 此外,需要执行管理过程来管理分片和租户填充。 例如,必须设计相应的过程来添加和删除分片,以及在分片之间移动租户数据。 一种缩放方式是添加一个新分片并在其中填充新租户。 在其他时候,可将密集填充的分片拆分成两个不太密实的分片。 移动或停用多个租户后,可将稀疏填充的分片合并在一起。 合并会导致资源利用变得更加经济高效。 还可以在分片之间移动租户,以均衡工作负荷。

SQL 数据库提供一个可与分片库和目录数据库结合使用的拆分/合并工具。 提供的应用可以拆分与合并分片,并可以在分片之间移动租户数据。 应用还会在执行这些操作期间维护目录,将受影响的租户标记为已脱机,然后移动这些租户。 移动后,应用会使用新映射再次更新目录,并将租户标记为已重新联机。

小型数据库更易于管理

通过在多个数据库之间分配租户,分片多租户解决方案可以生成更易于管理的小型数据库。 例如,将特定的租户还原到以前的某个时间点现在涉及到从备份中还原单个小型数据库,而不是从包含所有租户的大型数据库中还原。 可以选择数据库大小以及每个数据库的租户数,以均衡工作负荷与管理工作量。

架构中的租户标识符

根据所用的分片方法,可能需要对数据库架构施加额外的约束。 SQL 数据库拆分/合并应用程序要求架构包含分片键,这通常是租户标识符。 租户标识符是所有分片表的主键中的前导元素。 租户标识符可让拆分/合并应用程序快速找到和移动与特定租户关联的数据。

分片的弹性池

可将分片多租户数据库放在弹性池中。 一般而言,在一个池中放置许多单租户数据库,与在少量多租户数据库中放置许多租户的经济高效性相当。 当有大量的相对不活跃租户时,多租户数据库就很有优势。

H. 混合分片多租户数据库模型

在混合模型中,所有数据库在其架构中包含租户标识符。 这些数据库都能存储多个租户,并且可以分片。 因此,在架构的意义上,它们都是多租户数据库。 但实际上,其中一些数据库只包含一个租户。 不管怎样,给定数据库中存储的租户数量不会对数据库架构造成影响。

移动租户

随时可将特定的租户移到其自身的多租户数据库中。 也随时可以改变主意,将租户移回到包含多个租户的数据库中。 此外,在预配新数据库时,还可将租户分配到新的单租户数据库中。

当可识别的租户组的资源需求有很大差异时,混合模型的优势将很明显。 例如,假设无法向参与免费试用的租户提供与订阅租户相同的性能级别。 策略可以是将处于免费试用阶段的租户存储在由所有免费试用租户共享的某个多租户数据库中。 当某个免费试用租户订阅“基本”服务层级时,可将该租户移到可能包含更少租户的另一个多租户数据库中。 可将购买高级服务层的订阅者移动到其自己的新单租户数据库中。

在此混合模型中,可将订阅者租户的单租户数据库放在资源池中,以减少每个租户的数据库成本。 “每个租户各有数据库”模型中也采用了这种做法。

I. 租户模型的比较

下表汇总了主要租户模型之间的差异。

度量 独立应用 每个租户各有数据库 分片多租户
缩放 (1-100 s) (1-100,000 s) 无限制 (1-1,000,000s)
租户隔离 低;任何单租户(即独自在 MT 数据库中的租户)除外。
每个租户的数据库成本 高;大小根据峰值而定。 低;使用池。 最低,适用于 MT 数据库中的小租户。
性能监视和管理 仅限每租户 聚合 + 每租户 聚合;不过,对于单租户,将应用“仅限每租户”模式。
开发复杂性 中等;受分片影响。
操作复杂性 低到高。 单个操作较简单,大规模操作较复杂。 低到中等。 模式可以解决大规模操作的复杂性。 低到高。 单个租户的管理比较复杂。