返回介绍

设计面向微服务构成的应用程序

发布于 2025-02-23 23:15:31 字数 9390 浏览 0 评论 0 收藏 0

本部分重点介绍开发假设服务器端企业应用程序。

应用程序规范

假设应用程序执行业务逻辑、 访问数据库,并返回 HTML、 JSON 或 XML 响应处理请求。 我们将假定该应用程序必须支持各种客户端,包括桌面浏览器运行单页面应用程序 (Spa)、 传统 web 应用程序、 移动 web 应用和本机移动应用。 应用程序还可能会公开一个 API,使第三方使用。 它还应该能够以异步方式将其微服务或外部应用程序的集成,以便的方法将帮助的微服务对于部分故障的复原能力。

应用程序将这些类型的组件包括:

  • 表示组件。 这些是负责处理用户界面和使用远程服务。
  • 域或业务逻辑。 这是应用程序的域的逻辑。
  • 数据库访问逻辑。 这包括数据访问组件负责访问数据库 (SQL 或 NoSQL)。
  • 应用程序集成逻辑。 这包括主要基于消息代理的消息传递通道。

应用程序需要高可伸缩性,同时允许其垂直的子系统来自主,向外扩展,因为某些子系统需要比其他的多个可伸缩性。

应用程序必须能够在多个基础结构环境 (多个公共云基础架构并在本地) 部署,理想情况下应该可以跨平台,可以轻松地将从 Linux 为 Windows (反之亦然)。

开发团队上下文

我们还假设以下关于应用程序的开发过程:

  • 必须将重点放在应用程序的不同业务区域上的多个开发团队。
  • 新的团队成员必须提高工作效率快速,以及应用程序必须易于理解和修改。
  • 应用程序将具有的长期发展和不断变化的业务规则。
  • 你需要良好的长期可维护性意味着具有灵活性,同时能够使用在其他子系统上的最小影响更新多个子系统实现将来新更改时。
  • 你想做法持续集成和连续部署的应用程序。
  • 你想要利用新兴技术 (框架,编程语言,等等) 时不断演变的应用程序。 您不想要使应用程序的完整迁移,在迁移到新的技术,因为这将导致高成本,并影响的可预测性和应用程序的稳定性。

选择一种体系结构

应用程序部署体系结构应该是什么? 对于应用程序,以及开发上下文中,规范强烈建议你应通过将其分解到自治子系统中的协作微服务和容器,窗体,其中 microservice 设计应用程序是一个容器。

在此方法中,每个服务 (容器) 实现一组提供一致性和较窄相关的函数。 例如,应用程序可能包含目录服务,服务、 购物篮服务、 用户配置文件服务、 等排序等服务。

微服务通信使用协议如 HTTP (REST),但也以异步方式 (即 AMQP) 只要有可能,尤其是当传播使用更新集成事件。

开发和部署为独立于另一个容器微服务时。 这意味着,可以开发和部署某些 microservice 而不会影响其他子系统,开发团队。

每个微服务都有自己的数据库,使其能够从其他微服务完全分离。 如有必要,从不同的微服务的数据库之间的一致性被实现使用 (通过逻辑事件 bus) 的应用程序级集成事件的处理命令和查询责任分离 (CQRS) 中。 正因如此,业务约束必须接受多个微服务之间的最终一致性和相关数据库。

eShopOnContainers: 用于.NET 核心和微服务部署使用容器的引用应用程序

以便你可以专注于体系结构和技术而不是你可能不知道 hypothetic 业务领域的考虑,我们已选择的已知的业务域 — 即的简化的电子商务 (e-式应用商店) 应用程序提供的目录产品,接受来自客户的订单,验证清单,并执行其他业务功能。 此容器基于应用程序的源代码位于 eShopOnContainers GitHub 存储库。

该应用程序包含多个子系统,包括多个应用商店 UI 前端 (Web 应用程序和本机移动应用程序),以及后端微服务和容器的所有所需的服务器端操作。 图 8-1 显示引用应用程序的体系结构。

图 8-1 。 EShopOnContainers 引用演示直接的微服务构成客户端通信和事件 bus 的应用程序

宿主环境 。 在图 8-1,你会看到一个 Docker 主机中部署的多个容器。 部署到使用 docker 一台 Docker 主机时,会出现此情况的编写命令。 但是,如果你是使用 orchestrator 或容器群集时,每个容器无法在另一台主机 (节点) 中运行,并且任何节点无法运行任意数量的容器,如我们前面所述体系结构节中。

通信体系结构 。 EShopOnContainers 应用程序使用两个通信类型,具体取决于功能的操作 (而不是更新和事务的查询) 的类型:

  • 直接微服务构成客户端通信。 接受更新或从客户端应用程序的事务处理命令时,这用于查询和。
  • 基于事件的异步通信。 通过在微服务之间传播更新,或与外部应用程序集成事件总线发生这种情况。 可以使用任何如 RabbitMQ,或使用 Azure Service Bus、 NServiceBus、 MassTransit 或 Brighter 等的更高级别的服务总线的消息传递代理基础结构技术实现的事件总线。

作为一套微服务容器的形式部署应用程序。 客户端应用程序可以与这些容器通信以及微服务之间进行通信。 如前文所述,此初始体系结构使用直接微服务构成客户端通信体系结构,这意味着,直接客户端应用程序可以发出请求到每个微服务。 每个微服务具有类似 https://servicename.applicationname.companyname 公共终结点。 如果需要,每个微服务可以使用其他 TCP 端口。 在生产中,URL 将映射到微服务的负载平衡器,其中将请求分布到可用的微服务实例。

API 网关 vs 的重要说明。在 eShopOnContainers 的直接通信。 如本指南的体系结构部分中所述,直接微服务构成客户端通信体系结构可以在生成的大型复杂基于微服务构成的应用程序有缺点。 但它可以对已经足够好一个小的应用程序,如 eShopOnContainers 中启动应用程序,其目标是要专注于更简单的获取的 Docker 容器基于应用程序,并且我们不想创建可以影响单个整体 API 网关微服务的开发自治。

但是,如果你要设计大型基于微服务构成的应用程序的微服务数十个,我们强烈建议你考虑 API 网关模式,如我们的体系结构部分中所述。 无法重构此体系结构决策后立即可供生产应用程序和专门进行外观考虑为远程客户端。 具有多个的自定义 API 网关具体取决于客户端应用程序的外观可以提供有关每个客户端应用程序的不同的数据聚合的好处以及可以向客户端应用隐藏内部微服务或 Api 和单个该层中授权。

但是,并且提到过,请注意针对大型和整体 API 网关,可能会终止微服务的开发自治。

每个微服务构成的数据自主性

在示例应用程序,每个微服务拥有其自己的数据库或数据源,并且每个数据库或数据源部署为另一个容器。 这种设计决策进行仅以方便开发人员可以从 GitHub 获取代码、 克隆它,并在 Visual Studio 或 Visual Studio Code 中打开它。 或,或者,它可以轻松地编译自定义的 Docker 映像使用.NET 核心 CLI 和 Docker CLI 中,然后部署和在 Docker 开发环境中运行。 两种方式的容器用于数据源的允许开发人员生成和部署在几分钟内,而无需设置外部数据库或任何其他数据源具有对基础结构 (云中或本地) 的硬依赖项。

在实际生产环境中,高可用性和可伸缩性,数据库应基于数据库服务器中的云或本地,但不是在容器。

因此,部署微服务 (和即使对于此应用程序中的数据库) 的单位为 Docker 容器,并且引用应用程序是一个多容器应用程序,可满足微服务原则。

其他资源

一个基于微服务构成的解决方案的优点

像这样一个基于 microservice 解决方案带来诸多好处:

每个微服务是相对较小-易于管理和发展 。 尤其是在下列情况下:

  • 很容易开发人员了解并快速开始使用良好的工作效率。
  • 这使得开发人员提高工作效率,快速、 启动容器。
  • IDE 类似于 Visual Studio 可以负载较小项目快,使开发人员工作效率。
  • 每个微服务可以设计、 开发和部署独立于其他的微服务,提供灵活性,因为它是更轻松地频繁部署微服务的新版本。

可以横向扩展应用程序的各个区域 。 例如,目录服务或购物篮服务可能需要向外扩展,但不是排序的过程。 微服务基础结构将更高效减少比整体体系结构,向外缩放时使用的资源。

你可以将多个团队的开发工作划分 。 每个服务可以拥有的是单个开发团队。 每个团队可以管理、 开发、 部署和缩放其服务独立于团队的其余部分。

问题是更好隔离 。 如果一个服务时出现问题,只有该服务最初影响 (除非错误设计使用时,直接之间的相关性微服务),和其他服务可以继续处理请求。 相比之下,整体部署体系结构中的一个异常的组件可以关闭整个系统中,尤其是当涉及资源,例如内存泄漏。 此外时微服务中的问题得以解决后,, 可以部署仅受影响的微服务,而不会影响应用程序的其余部分。

你可以使用最新技术 。 因为你可以开始独立开发服务,然后运行它们并排 (得益于容器和.NET Core),你可以开始而不停滞在较旧的堆栈或框架,用于整个迅速地使用的最新技术和框架应用程序。

一个基于微服务构成的解决方案的不足之处

像这样一个基于 microservice 解决方案还存在一些缺点:

分布式应用程序 。 分发应用程序的开发人员增加复杂性,当设计和构建这些服务。 例如,开发人员必须实现 interservice 通信使用协议,如 HTTP 或 AMPQ,增加了用于测试和异常处理的复杂性。 它还添加到系统的延迟。

部署的复杂性 。 拥有数十微服务类型,并需要高可伸缩性 (它需要能够创建每个服务的多个实例和这些服务分摊到多个主机) 的应用程序的方法来 IT 运营和管理部署的复杂性度很高。 如果你不使用面向微服务的基础结构 (如 orchestrator 和计划程序),其他的复杂性可能需要比业务应用程序本身的更多的开发工作。

原子事务 。 通常多个微服务之间的原子事务中不可能。 业务要求需要采用多个微服务之间的最终一致性。

增加全局资源需求 (总内存、 驱动器和网络资源的所有服务器或主机)。 在许多情况下,使用微服务方法时,将整体应用程序时所需的基于微服务构成的新应用程序的全局资源量将大于原始的整体应用程序的基础结构需求。 这是因为更高程度的粒度和分布式的服务需要更具有全局性占用的资源。 资源的增加的使用给定低成本的常规和一个优势是能够扩大相比长期成本时不断演变的整体应用程序的应用程序只是某些区域中的资源,但是,是通常为一个很好权衡大,长期的应用程序。

直接 client‑to‑microservice 通信问题 。 大型,使用数十个微服务应用程序时,有挑战和限制如果应用程序要求直接微服务构成客户端通信。 一个问题是客户端的需求和每个微服务公开的 Api 的潜在不匹配。 在某些情况下,客户端应用程序可能需要进行许多单独的请求,以构成的用户界面,这会通过 Internet 效率低下,并将对移动网络不切实际。 因此,客户端应用程序中对后端系统的请求应将最小化。

与直接微服务构成客户端通信的另一个问题是某些微服务可能正在使用不是 Web 友好的协议。 一个服务可能使用的二进制协议,而另一个服务可能使用 AMQP 消息。 这些协议不是 firewall‑friendly,最好在内部使用。 通常情况下,应用程序应使用在防火墙外的通信协议,如 HTTP 和 Websocket。

尚未使用此直接 client‑to‑service 方法的另一个缺点是,它使得难以重构这些微服务的协定。 随着时间的推移开发人员可能想要更改系统分区到服务的方式。 例如,它们可能会合并两个服务或拆分为两个或多个服务的服务。 但是,如果客户端直接与服务进行通信,则执行这种重构可以中断与客户端应用程序兼容性。

中所述的体系结构部分,在设计和构建复杂的应用程序基于微服务时,你可以考虑使用多个的细化 API 网关而不是更简单的直接 client‑to‑microservice 通信方法。

分区微服务 。 最后,无论微服务体系结构采用哪种方法,另一个难题确定如何分区到多个微服务端到端应用程序。 如本指南的体系结构部分中所述,有几种技术和您可以采取的方法。 基本上,你需要识别的区域的应用程序从其他区域分隔和具有硬依赖项的数量较少。 在许多情况下,这是用例通过到服务分区对齐的。 例如,在我们电子商店的应用程序,我们具有一排序的服务,它负责与订单过程相关的所有业务逻辑。 我们还提供目录服务和购物篮服务实现其他功能。 理想情况下,每个服务应具有仅职责一小部分。 这是类似于单独责任原则 (SRP) 应用于类,以指出,一个类只能有一个确实需要更改。 但在这种情况下,它是有关微服务,因此该作用域将是大于单个类。 最重要的是,微服务必须是完全自治、 端到端,包括负责其自己的数据源。

与内部体系结构和设计模式的外部

外部体系结构是由多个服务,按照本指南的体系结构部分所述的原则的微服务体系结构。 但是,根据每个微服务,并独立于你选择的高级微服务体系结构的性质,它很常见,并且有时最好具有不同的内部体系结构,每种为基于不同的模式,不同微服务。 微服务甚至可以使用不同的技术和编程语言。 图 8-2 演示了这种多样性。

图 8-2 。 外部与内部体系结构和设计

例如,在我们eShopOnContainers示例中,目录、 购物篮和用户配置文件微服务是简单 (基本上,CRUD 子系统)。 因此,其内部体系结构和设计非常简单。 但是,你可能必须其他微服务,如排序 microservice,这是更复杂,并且与域复杂性度很高表示不断变化的业务规则。 在类似这样的情况下,你可能想要实现更高级的模式中特定的微服务,通过域驱动设计 (DDD) 方法定义为我们在中做的一样eShopOnContainers排序微服务。 (我们将查看更高版本的实现进行说明这部分中的这些 DDD 模式eShopOnContainers排序微服务。)

对于每个微服务使用的不同技术的另一个原因可能是每个微服务的性质。 例如,它可能是更好的做法使用功能的编程语言,如 F#,或者如果你正面向 AI 和机器学习域,而不是更加面向对象的编程语言 C 等甚至如 R 语言#。

底部行是每个微服务可以有不同的内部体系结构,能根据不同的设计模式。 并非所有微服务应使用来实现高级的 DDD 模式,因为,将会过度工程它们。 同样,不应作为 CRUD 组件实现包含不断变化的业务逻辑的复杂微服务或您可以得到质量较低的代码。

新体系: 多个体系结构模式和 polyglot 微服务

有许多软件架构师和开发人员使用的体系结构模式。 以下是一些 (即混合体系结构样式和体系结构模式):

你也可以生成与许多技术和语言,如 ASP.NET 核心 Web Api、 NancyFx、 ASP.NET 核心 SignalR (适用于.NET 核心 2)、 F 的微服务#,Node.js、 Python、 Java、 c + +、 GoLang,和的详细信息。

重要的一点是任何特定的体系结构模式或样式,也不任何特定的技术,最适合所有情况。 图 8-3 显示了一些方法和技术 (尽管不是在任何特定的顺序),无法在不同的微服务中使用。

图 8-3 。 多体系结构模式和 polyglot 微服务世界

中所示图 8-3,应用程序中许多微服务组成 (绑定上下文中在域驱动设计术语中或只需"子系统"作为自治微服务),您可能会以不同的方式实现每个微服务。 每个可能具有不同的体系结构模式,并使用不同的语言和具体取决于应用程序的性质、 业务需求和优先级的数据库。 在某些情况下可能是相似的微服务。 但这不是通常情况下,因为每个子系统的上下文边界和要求通常不同。

例如,对于简单 CRUD 维护应用程序,它可能毫无意义设计和实现 DDD 模式。 但核心域或核心业务,你可能需要应用更高级的模式为处理独特业务的不断变化的业务规则的复杂性。

尤其是当你处理大型应用程序由多个子系统,不应该应用基于单个体系结构模式同一个顶级体系结构。 例如,CQRS 不应作为整个应用程序的顶级结构应用,但可能适用于一组特定的服务。

没有任何银级的项目符号或每个给定的用例的正确的体系结构模式。 不能有"一个体系结构模式规则其全部。" 具体取决于每个微服务构成的优先级,必须选择不同的方法对于每个,如以下各节中所述。

以前 下一步

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文