部署缩放单元模式涉及预配、管理和监视异构资源组以托管和操作多个工作负载或租户。 每个副本被称为缩放单元,有时也被称为服务单元或单元。 在多租户环境中,每个缩放单元可为预定义数量的租户提供服务。 可以部署多个缩放单元,以便准线性地缩放解决方案并为不断增加的租户提供服务。 此方法可以提高解决方案的可伸缩性,允许跨多个区域部署实例,以及隔离客户数据。
备注
有关设计 Azure 多租户解决方案的详细信息,请参阅在 Azure 上构建多租户解决方案。
在云中托管应用程序时,请务必考虑应用程序的性能和可靠性要求。 如果托管解决方案的单个实例,可能会受到以下限制:
- 规模限制。 部署应用程序的单个实例可能会导致自然缩放限制。 例如,使用的服务可能对入站连接、主机名、TCP 套接字或其他资源施加限制。
- 非线性缩放或成本。 解决方案的某些组件可能不会根据请求数量或数据量线性缩放。 达到阈值后,性能可能骤然下降或者成本骤然增加。 例如,在使用某个数据库时,你可能发现增加更多容量(纵向扩展)的边际成本变得过高,而横向扩展是更经济高效的策略。
- 客户隔离。 你可能需要将某些客户的数据与其他客户的数据相隔离。 同样,可能有些客户需要比其他客户更多的系统服务资源,你可以考虑在不同的基础结构集上将他们分组。
- 处理单租户和多租户实例。 你可能有一些大客户需要他们自己的独立解决方案实例。 你可能还有一个可以共享多租户部署的小型客户池。
- 复杂的部署要求。 你可能需要以受控方式将更新部署到服务,并在不同的时间部署到不同的客户群子集。
- 更新频率。 有些客户可以容忍系统频繁更新,而有些客户不愿意承受风险,希望为他们的请求提供服务的系统不经常更新。 将这些客户部署到隔离的环境中可能有帮助。
- 地理或地缘政治限制。 为了实现低延迟或遵守数据主权要求,可将某些客户部署到特定的区域。
这些限制通常适用于构建服务型软件 (SaaS) 的独立软件供应商 (ISV),这种软件采用多租户设计。 但是,同样的限制也适用于其他应用场景。
为了避免这些问题,请考虑在缩放单元中将资源分组,并预配缩放单元的多个副本。 每个缩放单元将托管租户的子集并为其提供服务。 标记彼此独立运行,且可以独立部署和更新。 单个地理区域可能包含单个缩放单元,也可能包含多个缩放单元以允许在区域内横向扩展。 缩放单元包含客户的子集。
无论解决方案使用的是基础结构即服务 (IaaS)、平台即服务 (PaaS) 组件还是混合使用两者,都可以应用部署缩放单元。 通常,IaaS 工作负载需要更多干预才能缩放,因此对于 IaaS 繁重型工作负载,可以使用该模式来实现横向扩展。
缩放单元可用于实现部署环。 如果不同的客户希望以不同的频率接收服务更新,可将他们分组到不同的缩放单元,并以不同的频率为每个缩放单元部署更新。
由于缩放单元彼此独立运行,因此数据是隐式分片的。 此外,单个缩放单元可以利用进一步的分片在内部实现可伸缩性和弹性。
许多 Azure 服务(包括应用服务、Azure Stack 和 Azure 存储)在内部使用部署缩放单元模式。
部署缩放单元与地理节点相关,但两者不同。 在部署缩放单元体系结构中,将部署系统的多个独立实例,其中包含客户和用户的子集。 在地理节点中,所有实例可为任何用户的请求提供服务,但此体系结构的设计和构建通常更复杂。 此外还可以考虑在一个解决方案中混合两种模式;本文稍后将介绍的流量路由方法就是这种混合应用场景的一个例子。
由于部署相同组件的相同副本所涉及的复杂性,良好的 DevOps 实践对于确保成功实现此模式至关重要。 考虑将基础结构描述为代码,例如使用 Bicep、JSON Azure 资源管理器模板(ARM 模板)、Terraform 和脚本。 使用这种方法可以确保每个缩放单元的部署可预测且可重复。 此外,还可以减少人为失误的可能性,例如缩放单元之间的配置意外地不匹配。
可以自动将更新同时部署到所有缩放单元,在这种情况下,可以考虑使用 Bicep 或资源管理器模板等技术来协调基础结构和应用程序的部署。 或者,可以先向某些缩放单元逐步部署更新,然后再向其他缩放单元逐步部署更新。 考虑使用 Azure Pipelines 或 GitHub Actions 之类的发布管理工具来协调对每个缩放单元的部署。 有关详情,请参阅:
认真考虑部署的 Azure 订阅和资源组的拓扑:
- 订阅通常会包含单个解决方案的所有资源,因此我们一般会考虑对所有缩放单元使用单个订阅。 但是,某些 Azure 服务实施订阅范围的配额,因此如果你使用此模式来实现较高程度的横向扩展,可能需要考虑在不同的订阅中部署缩放单元。
- 资源组通常用于部署具有相同生命周期的组件。 如果你打算一次性将更新部署到所有缩放单元,请考虑使用单个资源组来包含所有缩放单元的所有组件,并使用资源命名约定和标记来标识属于每个缩放单元的组件。 或者,如果你打算单独将更新部署到每个缩放单元,请考虑将每个缩放单元部署到其自身的资源组中。
使用负载和性能测试来确定给定缩放单元大约可以容纳的负载。 负载指标可以基于单个缩放单元可以容纳的客户/租户数量,也可以基于缩放单元中的组件发出的服务指标。 确保采取充分的检测措施来度量给定缩放单元何时接近其容量限制,以及能否快速部署新的缩放单元来应对需求。
如果每个缩放单元可单独寻址,则部署缩放单元模式可以顺利工作。 例如,如果 Contoso 要将同一个 API 应用程序部署到多个缩放单元,则他们可以考虑使用 DNS 将流量路由到相关缩放单元:
unit1.aus.myapi.contoso.com
将流量路由到澳大利亚区域中的缩放单元unit1
。unit2.aus.myapi.contoso.com
将流量路由到澳大利亚区域中的缩放单元unit2
。unit1.eu.myapi.contoso.com
将流量路由到欧洲区域中的缩放单元unit1
。
然后客户端负责连接到正确的缩放单元。
如果所有流量需要单个入口点,可以使用流量路由服务来解析给定请求、客户或租户的缩放单元。 流量路由服务将客户端定向到缩放单元的相关 URL(例如,使用 HTTP 302 响应状态代码),或者充当反向代理,在客户端不知情的情况下将流量转发到相关缩放单元。
集中式流量路由服务可能是设计上较为复杂的组件,尤其是当解决方案跨多个区域运行时。 考虑将流量路由服务部署到多个区域(可能包括缩放单元部署到的每个区域),并确保数据存储(将租户映射到缩放单元)同步。 流量路由组件本身可以是地理节点模式的一个实例。
例如,可以部署 Azure API 管理来充当流量路由服务角色。 它可以通过在存储租户与缩放单元之间的映射的 Azure Cosmos DB 集合中查找数据来确定请求的适当缩放单元。 然后 API 管理可以动态设置相关缩放单元的 API 服务的后端 URL。
若要启用请求异地分发和流量路由服务的异地冗余,可将 API 管理部署到多个区域,或者可以使用 Azure Front Door 将流量定向到最靠近的实例。 可为 Front Door 配置后端池,以便能够将请求定向到最靠近的可用 API 管理实例。 如果应用程序不是通过 HTTP/S 公开的,则可以使用跨区域 Azure 负载均衡器将传入调用分发到区域 Azure 负载均衡器。 可以使用 Azure Cosmos DB 的全球分发功能在每个区域中保持映射信息的更新状态。
如果解决方案中包含流量路由服务,请考虑它是否充当网关,因此可为令牌验证、限制和授权等其他服务执行网关卸载。
请考虑以下示例流量路由体系结构,它使用 Azure Front Door、Azure API 管理和 Azure Cosmos DB 进行全局流量路由,然后使用一系列特定于区域的缩放单元:
假设某个用户平时居住在纽约。 其数据存储在“美国东部”区域的缩放单元 3 中。
如果该用户前往加利福尼亚,然后访问系统,则其连接可能会通过“美国西部 2”区域路由,因为该区域在地理位置上与该用户发出请求时所处的位置最靠近。 但是,该请求最终必须由缩放单元 3 提供服务,因为这是该用户的数据的存储位置。 流量路由系统确保将请求路由到正确的缩放单元。
在决定如何实现此模式时,应考虑以下几点:
- 部署过程。 部署多个缩放单元时,强烈建议使用自动化且完全可重复的部署过程。 可考虑使用 Bicep、JSON ARM 模板或 Terraform 模块以声明方式定义缩放单元,并确保定义的一致性。
- 跨缩放单元操作。 将解决方案独立部署到多个缩放单元时,“我们的所有缩放单元中有多少客户?”之类的问题可能更难以回答。 可能需要针对每个缩放单元执行查询并聚合结果。 或者,考虑让所有缩放单元将数据发布到一个集中的数据仓库中以进行合并报告。
- 确定横向扩展策略。 缩放单元的容量有限,可以使用代理指标(例如可部署到缩放单元的租户数)来定义容量。 必须监视每个缩放单元的可用容量和已用容量,并前瞻性地部署更多的缩放单元,以便能够将新租户定向到它们。
- 最小缩放单元数。 使用部署缩放单元模式时,建议至少为解决方案部署两个缩放单元。 如果只部署一个缩放单元,则很容易意外地将假设硬编码到代码或配置中,而这些假设在横向扩展时不适用。
- 成本。 部署缩放单元模式涉及到部署基础结构组件的多个副本,这可能会大幅增加解决方案的操作成本。
- 在缩放单元之间移动。 由于每个缩放单元都是独立部署和操作的,因此在缩放单元之间移动租户可能很困难。 应用程序需要通过自定义逻辑将有关给定客户的信息传输到不同的缩放单元,然后从原始缩放单元中删除租户的信息。 此过程可能需要通过一个背板在缩放单元之间进行通信,从而进一步增大了整个解决方案的复杂性。
- 流量路由。 如上文所述,将流量路由到给定请求的正确缩放单元可能需要通过附加的组件将租户解析到缩放单元。 而此组件可能需要高度可用。
- 共享组件。 可能有一些组件在缩放单元之间共享。 例如,如果你为所有租户共享某个单页应用,请考虑将该应用部署到一个区域,并使用 Azure CDN 在全球复制它。
此模式可用于解决以下问题和需求:
- 可伸缩性的自然限制。 例如,如果某些组件无法或者不应扩展到超过特定数量的客户或请求,请考虑使用缩放单元进行横向扩展。
- 将某些租户与其他租户隔离的需求。 如果出于安全考虑,不能将某些客户与其他客户一起部署到多租户缩放单元,可以将他们部署到其自己的隔离缩放单元中。
- 需要同时将某些租户部署在不同版本的解决方案中。
- 需要将多区域应用程序中每个租户的数据和流量定向到特定区域。
- 希望在服务中断期间实现复原。 由于缩放单元彼此独立,如果服务中断影响了单个缩放单元,部署到其他缩放单元的租户应该不会受到影响。 这种隔离有助于控制事件或服务中断的“冲击范围”。
此模式不适合以下解决方案:
- 不需要高度扩展的简单解决方案。
- 可以在单个实例中轻松横向扩展或纵向扩展的系统,例如通过增大应用程序层的大小或通过增加数据库和存储层的预留容量进行扩展。
- 需要将其中的数据复制到所有已部署实例的解决方案。 对于这种方案,请考虑使用地理节点模式。
- 仅需要扩展某些组件而不需要扩展其他组件的解决方案。 例如,考虑是否可以通过将数据存储分片而不是部署所有解决方案组件的新副本来扩展解决方案。
- 仅由静态内容组成的解决方案,例如前端 JavaScript 应用程序。 考虑将此类内容存储在存储帐户中并使用 Azure CDN。
架构师应评估如何在其工作负荷的设计中使用“部署标记模式”,以解决 Azure Well-Architected Framework 支柱中涵盖的目标和原则。 例如:
支柱 | 此模式如何支持支柱目标 |
---|---|
卓越运营有助于通过标准化流程和团队凝聚力来实现工作负荷质量。 | 此模式支持不可变的基础结构目标、高级部署模型,并且可以促进安全部署实践。 - OE:05 基础结构即代码 - OE:11 安全部署实践 |
性能效率通过在缩放、数据和代码方面进行优化, 帮助工作负载高效地满足需求。 | 此模式通常与工作负载中定义的缩放单元保持一致:由于需要超出单个缩放单元提供的额外容量,因此会部署一个额外的部署标记来横向扩展。 - PE:05 缩放和分区 |
与任何设计决策一样,请考虑对可能采用此模式引入的其他支柱的目标进行权衡。
- 基础结构即代码。 例如,Bicep、资源管理器模板、Azure CLI、Terraform、PowerShell、Bash。
- Azure Front Door,它可以将流量路由到特定缩放单元或流量路由服务。
以下示例部署某个简单 PaaS解决方案的多个缩放单元,每个缩放单元中有一个应用服务和一个 SQL 数据库。 虽然可以在任何区域中配置缩放单元来支持模板中部署的服务,但出于演示目的,此模板在“美国西部 2”区域中部署了两个缩放单元,并在“西欧”区域中部署了另一个缩放单元。 在一个缩放单元中,应用服务接收自身的公共 DNS 主机名,并可以独立于所有其他缩放单元接收连接。
警告
以下示例使用 SQL Server 管理员帐户。 在应用程序中使用管理帐户通常不是良好的做法。 对于实际应用程序,请考虑使用托管标识从应用程序连接到 SQL 数据库,或使用最低特权帐户。
单击以下链接来部署解决方案。
以下示例部署某个流量路由解决方案的实现,可将其用于某个虚构 API 应用程序的一组部署缩放单元。 为了能够地理分发传入请求,Front Door 连同多个 API 管理实例一起部署在消耗层上。 每个 API 管理实例从请求 URL 中读取租户 ID,并从异地分布的 Azure Cosmos DB 数据存储中查找请求的相关缩放单元。 然后将该请求转发到相关的后端缩放单元。
单击以下链接来部署解决方案。
本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。
主要作者:
- John Downs | 首席项目经理
其他参与者:
- Daniel Larsen | FastTrack for Azure 首席客户工程师
- Angel Lopez | Azure Patterns and Practices,高级软件工程师
- Paolo Salvatori | FastTrack for Azure 首席客户工程师
- 阿森·弗拉基米尔斯基|首席工程师,FastTrack for Azure
要查看非公开的 LinkedIn 个人资料,请登录到 LinkedIn。