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

使用域驱动的设计将整体应用程序迁移到微服务

ASP.NET

本文介绍如何使用域驱动设计 (DDD) 将整体应用程序迁移到微服务。

整体应用程序通常是一个应用程序系统,其中所有相关模块都作为单个可部署的执行单元被打包在一起。 例如,它可能是在 Tomcat 上运行的 Java Web 应用程序 (WAR) 或是在 IIS 上运行的 ASP.NET 应用程序。 典型的整体应用程序使用分层设计,具有用于 UI、应用程序逻辑和数据访问的单独层。

典型的整体体系结构

这些系统从小规模开始,但往往会随着时间的推移而增长,以满足业务需求。 在某些时候,随着新功能的添加,整体应用程序可能会开始出现以下问题:

  • 系统的各个部分无法独立缩放,因为它们紧密耦合。
  • 由于存在紧密耦合的情况以及隐藏的依赖项,很难维护代码。
  • 测试变得更加困难,增加了引入漏洞的可能性。

这些问题可能成为未来增长和稳定的障碍。 团队在进行更改时会小心翼翼,特别是在原始开发人员不再处理项目且设计文档稀少或过时的情况下。

尽管存在这些限制,但整体设计可作为应用程序的起点。 整体通常是构建概念证明或最小可行产品的最快速路径。 在开发初期,整体往往:

  • 更易于构建,因为只有一个共享代码库。
  • 更易于调试,因为代码在单个进程和内存空间中运行。
  • 更容易推理,因为移动部件较少。

但是,随着应用程序的复杂性的增长,这些优势可能会消失。 大型整体通常越来越难以构建、调试和推理。 在部分情况下会弊大于利。 在弊大于利的情况下,就应将应用程序迁移到微服务体系结构。 与整体不同,微服务通常是分散的、松散耦合的执行单元。 下图显示了典型的微服务体系结构:

典型的设计微服务体系结构

将整体迁移到微服务需要大量的时间和投资,以避免故障或超支。 为了确保能成功地完全迁移,最好了解微服务带来的好处以及挑战。 优点包括:

  • 服务可以根据用户需求独立发展。
  • 服务可以独立缩放以满足用户需求。
  • 随着时间的推移,开发周期会更快,因为功能可以更快地发布到市场。
  • 服务是隔离的,且对故障的容忍度更高。
  • 单项服务的故障不会让整个应用程序崩溃。
  • 使用行为驱动的开发,测试变得更加连贯和一致。

有关微服务的优点和挑战的详细信息,请参阅微服务体系结构样式

应用域驱动设计

任何迁移策略都应允许团队以增量方式将应用程序重构为较小的服务,同时仍为最终用户提供服务的连续性。 以下是一般方法:

  • 停止向整体添加功能。
  • 拆分后端和前端。
  • 将整体分解并分离为一系列微服务。

要促进此类分解,应用域驱动设计 (DDD) 原则是一种切实可行的软件开发方法。

域驱动设计 (DDD) 是 Eric Evans 首先引入的软件开发方法。 DDD 需要充分了解要为其编写应用程序的域。 创建应用程序所需的域知识由理解它的人掌握,即域专家。

可将 DDD 方法以追溯方式应用于现有应用程序,以开始分解应用程序。

  1. 从通用语言开始,这是所有利益干系人共同使用的通用词汇。

  2. 确定整体应用程序中的相关模块,并将通用词汇表应用于这些模块。

  3. 定义整体应用程序的域模型。 领域模型是业务领域的抽象模型。

  4. 为模型定义边界上下文。 边界上下文是应用特定领域模型的领域中的边界。 使用明确定义的模型和职责应用显式边界。

步骤 4 中标识的边界上下文是重构为较小的微服务的候选项。 下图显示了覆盖有边界上下文的现有整体:

整体中的边界上下文

有关对微服务体系结构使用 DDD 方法的详细信息,请参阅使用域分析为微服务建模

使用粘附代码(防损层)

虽然执行此调查工作来清点整体应用程序,但可以通过应用 DDD 原则将新功能添加为单独的服务。 “粘附代码”允许整体应用程序代理对新服务的调用以获取新功能。

粘附代码以允许整体与新服务交互

粘附代码(适配器模式)有效地充当了防损层,确保新服务不会被整体应用程序所需的数据模型污染。 粘附代码有助于调解两者之间的交互,并确保仅传递新服务所需的数据,从而实现兼容性。

通过重构过程,团队可以清点整体应用程序,并确定微服务重构的候选项,同时使用新服务建立新功能。

有关防损层的详细信息,请参阅防损层模式

创建表示层

下一步是将表示层与后端层分开。 在传统的 n 层应用程序中,应用程序(业务)层往往是应用程序的核心组件,并且其中具有域逻辑。 这些粗粒度 API 与数据访问层交互,以从数据库中检索持久化数据。 这些 API 建立了到表示层的自然边界,并有助于将表示层分离到单独的应用程序空间中。

下图显示了从应用程序逻辑层和数据访问层中分离出来的表示层 (UI)。

API 网关模式

此图还引入了另一层,即 API 网关,其位于表示层和应用程序逻辑之间。 API 网关是一个外观层,它为表示层提供一致且统一的交互界面,同时允许下游服务独立发展,而不会影响应用程序。 API 网关可以使用 Azure API 管理等技术,并允许应用程序以 RESTful 方式进行交互。

可以使用团队具备专业知识的任何语言或框架(例如单页应用程序或 MVC 应用程序)开发表示层。 这些应用程序使用标准 HTTP 调用通过网关与微服务进行交互。 有关 API 网关的详细信息,请参阅在微服务中使用 API 网关

开始停用整体

在此阶段,团队可以开始剥离整体应用程序,并慢慢地将已由其边界上下文建立的服务提取到他们自己的微服务集中。 微服务可以为应用程序层公开一个 RESTful 接口,以便通过 API 网关进行交互,并准备好粘附代码,以便在特定情况下与整体进行通信。

使用 API 层

随着剥离进程的持续推进,最终将完全不再需要整体应用程序,且微服务将成功从整体中提取。 此时,可以安全地删除防损层(粘附代码)。

此方法是 Strangler Fig 模式 的一个示例,可用于以受控方式将整体分解为一组微服务。 随着时间的推移,现有功能会移动到微服务中,整体应用程序的规模和复杂性都将缩小,直至不再存在。

作者

本文由 Microsoft 维护, 最初由以下贡献者撰写。

主要作者:

若要查看非公开的 LinkedIn 个人资料,请登录到 LinkedIn。

后续步骤

当应用程序分解为构成微服务时,可以使用新式业务流程工具(如 Azure DevOps)来管理每个服务的生命周期。 有关详细信息,请参阅微服务体系结构的 CI/CD