【微服务架构】单片到微服务架构的模式和最佳实践

SEO Title
Monolithic to Microservices Architecture with Patterns & Best Practices

在本文中,我们将学习如何使用设计模式、原则和最佳实践来设计微服务架构。 我们将使用正确的架构设计模式和技术。
在本文结束时,您将了解如何在微服务分布式架构上设计系统以实现高可用性、高可扩展性、低延迟和对网络故障的弹性,从而处理数百万个请求。

msa

Event-Driven Architecture

本课程将是软件架构设计的旅程,逐步将架构单片演变为事件驱动的微服务。
我们将从设计处理少量请求的电子商务整体架构开始软件架构的基础知识。

msa

Journey of Design Architectures

之后逐步演变架构

  • 分层架构
  • SOA
  • 微服务
  • 最后是事件驱动的微服务架构

一起设计处理数百万个请求。


带课程的逐步设计架构


在本课程中,我们将学习如何使用设计模式、原则和最佳实践来设计微服务架构。我们将从设计单体到事件驱动的微服务开始,并一起使用正确的架构设计模式和技术。


文章流


在文章流中将既有理论信息又有实践信息;

  • 我们将学习一个特定的模式,我们应该使用的原因和位置
  • 之后,我们将看到应用这些模式的参考架构
  • 之后,我们将应用这个新学习的模式来设计我们的架构
  • 最后,我们将决定哪些技术可以作为该架构的选择。

所以我们将迭代和演化架构单体到事件驱动的微服务架构。


架构演进


我们将根据问题发展这些架构

  • 我们如何扩展应用程序?
  • 我们的应用程序需要处理多少个请求?
  • 我们的拱门可以接受多少秒的延迟?

因此,我们根据以下问题演变这些问题;

msa

可扩展性和可靠性是衡量您的应用程序对最终用户的服务程度的衡量标准。 如果我们的电子商务应用程序可以在没有明显停机的情况下为数百万用户提供服务,那么我们可以说该系统具有高度可扩展性和可靠性。 可扩展性和可用性可能是设计良好架构的主要因素。

  • 可扩展性=电子商务应用程序应该能够为数百万用户提供服务
  • 可用性 = 电子商务应用程序应该 24/7 可用
  • 可维护性=电子商务应用程序应该发展几年
  • 效率 = 电子商务应用程序应响应可接受的延迟,
  • 例如 < 2 秒 - 短响应延迟


每秒请求和可接受的延迟


好的,让我们谈谈可接受的延迟,
如果我们的应用程序被越来越多的用户使用,我们如何使我们的应用程序具有可接受的延迟?
请看表格;

msa

正如您在表中看到的,我们将启动一个小型电子商务应用程序,该应用程序仅获得 2K 并发用户,每秒获得 500 个请求。
我们将根据这些预期数量设计我们的电子商务架构。
在那之后,当我们的业务不断发展壮大时,它将需要更多的资源来容纳更大的请求数量,我们将看到如何根据这些数字来发展我们的架构。


单体架构


经过几十年的软件开发,有许多方法和模式演变而来,它们都有自己的好处和挑战。
因此,我们将从了解构建我们的电子商务应用程序的现有方法开始,然后发展和迁移到云。
为了理解云原生微服务,我们需要了解什么是单体应用程序,以及我们是如何从单体转向微服务的。

msa

对于遗留应用程序,我们可以说大多数遗留应用程序主要是作为一个单体架构来实现的。
如果一个项目的所有功能都存在于一个代码库中,
那么该应用程序被称为单片应用程序。在单体模式中,用户界面、业务代码和数据库调用等所有内容都包含在同一个代码库中。
所有应用程序关注点都包含在一个大型部署中。
即使是单体应用程序也可以在不同的层(如表示层、业务层和数据层)中进行设计,然后将该代码库部署为单个 jar/war 文件。
整体方法有几个优点,我们将在接下来的视频中讨论它们。但让我在这里说一些主要的优点和缺点。
由于它是单个代码库,因此很容易拉取并开始项目。
由于项目结构在 1 个项目中,并且易于调试跨不同模块的业务交互。
不幸的是,单体架构有很多缺点,我们可以这样说;

  • 随着时间的推移,它的代码量变得太大,这就是为什么它真的很难管理。
  • 难以在同一代码库中并行工作。
  • 难以在遗留的大型单体应用程序上实现新功能
  • 任何更改都需要部署整个应用程序的新版本。

等等..
如您所见,我们了解单体架构。


何时使用单体架构


即使是单体架构也有很多缺点,如果您正在构建小型应用程序,那么单体架构仍然是您可以应用于项目的最佳架构之一。因为,在许多方面,单体应用程序都很简单。
它们很简单:

  • 建造
  • 测试
  • 部署
  • 疑难解答
  • 垂直缩放(放大)
  • 非常简单快捷。

相对于需要熟练的开发人员来识别和开发服务的微服务,开发起来很简单。由于只部署了一个 jar/war 文件,因此更易于部署。

设计单体架构


在本节中,我们将逐步设计具有单体架构的电子商务应用程序。
我们将根据需求一一迭代架构设计。
我们应该始终从写下 FR(功能要求)和 NFR(非功能要求)开始。


功能要求

 

  • 列出产品
  • 按品牌和类别过滤产品
  • 将产品放入购物车
  • 申请折扣券并查看购物车中所有商品的总费用
  • 结帐购物车并创建订单
  • 列出我的旧订单和订单商品历史


非功能性要求

 

  • 可扩展性
  • 增加并发用户

此外,最好在我们的图片中添加原则以便始终记住它们。


原则

  • KISS
  • YAGNI


我们将在设计架构时考虑这些原则。

msa

如您所见,我们使用单体架构设计了我们的电子商务应用程序。
我们添加了大电子商务框,我们的电子商务应用程序的组件是什么;商店 UI、目录服务、SC 服务、折扣服务、订单服务。如您所见,这个传统 Web 应用程序的所有模块都是容器中的单个工件。
这个单体应用程序有一个包含所有模块的庞大代码库。如果向该应用程序引入新模块,则必须对现有代码进行更改,然后将具有不同代码的工件部署到 Tomcat 服务器。我们遵循我们的 KISS 原则,即保持简单。
我们将根据需求重构我们的设计,并逐步迭代在一起。


单体架构的可扩展性


如您所见,我们通过添加 2 个应用服务器并在客户端和电子商务应用程序之间的单体应用程序前面放置负载均衡器,通过水平扩展来扩展单体架构。
为了在单体架构上提供可扩展性。我们需要创建电子商务应用服务器。并将负载均衡器放在我们的应用程序前面。
基本上,负载均衡器将使用一致的哈希算法来容纳请求并将请求发送到我们的电子商务应用程序服务器。这将为服务器提供同等负载。


适配技术栈


我们将讨论技术选择——适应技术堆栈。

msa

正如您所看到的图像,我们已经为我们的电子商务整体应用程序选择了潜在的选项。 NGINX 是负载平衡和 Java 的非常好的选择——Oracle 是此类应用程序的标准实现。


微服务架构


微服务是可以协同工作并且可以自主/独立部署的小型企业服务。


来自 Martin Fowlers 微服务文章;


微服务架构风格是一种将单个应用程序开发为一组小服务的方法,每个服务都在自己的进程中运行并与轻量级机制(通常是 HTTP 或 gRPC API)进行通信。


所以我们可以说,微服务架构是一种云原生架构方法,其中应用程序由许多松散耦合且可独立部署的较小组件组成。


微服务

 

  • — 拥有自己的技术栈,包括数据库和数据管理模型;
  • — 通过 REST API、事件流和消息代理的组合相互通信;
  • — 按业务能力组织,分隔服务的线通常称为有界上下文。

在接下来的部分中,我们还将看到如何将微服务与有界上下文解耦。


微服务特征


微服务体积小、独立且松耦合。一个小型开发团队可以编写和维护服务。每个服务都是一个单独的代码库,可以由一个小型开发团队管理。
服务可以独立部署。团队无需重建和重新部署整个应用程序即可更新现有服务。
服务负责保存自己的数据或外部状态。这与传统模型不同,在传统模型中,单独的数据层处理数据持久性。


微服务架构的好处


敏捷。

 

  • 微服务最重要的特征之一是因为服务更小且可独立部署。
  • 小而专注的团队。
  • 微服务应该足够小,以至于单个功能团队可以构建、测试和部署它。


可扩展性。

 

  • 微服务可以独立扩展,因此您可以扩展需要较少资源的子服务,而无需扩展整个应用程序。


微服务架构的挑战


复杂。


微服务应用程序有很多服务需要协同工作并且应该创造价值。由于有很多服务,这意味着比单体应用程序有更多的移动部件。


网络问题和延迟。


因此,由于微服务很小并且与服务间通信进行通信,我们应该管理网络问题。


数据的完整性。


微服务有自己的数据持久化。因此,数据一致性可能是一个挑战。

设计微服务架构


在本节中,我们将逐步设计微服务架构。 根据需求一一迭代拱设计。

msa

我们在设计微服务架构和放置所有微服务的数据库时遵循了每服务数据库模式。 微服务由具有独立服务的单体应用程序模块分解而成。
所以现在这些数据库可以是多语言持久化的。 也就是说 Product ms 可以使用 NoSQL 文档数据库 SC ms 可以使用 NoSQL 键值对数据库, Order ms 可以根据 ms 数据存储要求使用 Relational 数据库。


发展架构


让我们看看微服务架构图,想想这个架构缺少什么? 这种架构的痛点是什么? 我们如何将这种架构发展为更好的架构,以提高可扩展性、可用性,能够容纳更多并发请求?

msa

看到 UI 和 Microservices 通信是直接的,而且似乎很难管理通信。
我们现在应该专注于微服务通信!


微服务通信


迁移到基于微服务的应用程序时,最大的挑战之一是改变通信机制。因为微服务是分布式的,微服务之间通过网络级别的服务间通信进行通信。每个微服务都有自己的实例和进程。
因此,服务必须使用服务间通信协议(如 HTTP、gRPC 或消息代理 AMQP 协议)进行交互。
由于微服务是独立开发和部署的服务的复杂结构,因此我们在考虑通信类型并将它们管理到设计阶段时应该小心。


微服务通信设计模式——API网关模式


如果您想设计和构建具有多个客户端应用程序的基于微服务的复杂应用程序,建议使用 API 网关模式。
该模式提供了一个反向代理来将请求重定向或路由到您的内部微服务端点。 API 网关为客户端应用程序提供单个端点,并在内部将请求映射到内部微服务。我们应该在客户端和内部微服务之间使用 API 网关。
API 网关可以处理授权等横切问题
因此,无需编写每个微服务,授权可以在集中式 API 网关中处理并发送到内部微服务。 api 网关还管理到内部微服务的路由,并能够在 1 个响应中聚合多个微服务请求。
总之,API 网关位于客户端应用程序和内部微服务之间。它充当反向代理并将请求从客户端路由到后端服务。它还提供横切关注点,如身份验证、SSL 终止和缓存。


设计 API 网关 — 微服务通信设计模式


我们将通过添加 API 网关模式来迭代我们的电子商务架构。

msa

您可以看到在单个入口点收集客户端请求并将请求路由到内部微服务的图像。
这将处理客户端请求并路由内部微服务,
还将多个内部微服务聚合到单个客户端请求中
并执行横切关注点,如身份验证和授权、速率限制和节流等。


发展架构


我们将继续发展我们的架构,但请查看当前的设计并思考如何改进设计?
这里有几个客户端应用程序连接到单个 API 网关。
我们应该小心这种情况,因为如果我们在这里放置一个单独的 api 网关,这意味着这里可能存在单点故障风险。
如果这些客户端应用程序增加,或者为 API 网关中的业务复杂性添加更多逻辑,这将是反模式。
所以我们应该用 BFF-backends-for-frontends 模式来解决这个问题。


Backends for Frontends 模式 BFF — 微服务通信设计模式


前端模式的后端基本上根据特定的前端应用程序分离 api 网关。所以我们有几个后端服务被前端应用程序使用,在它们之间我们放置 API 网关来处理路由和聚合操作。

但这会导致单点故障,所以为了解决这个问题,BFF 提供了创建多个 API 网关并根据它们的边界对客户端应用程序进行分组并将它们拆分为不同的 API 网关。

msa

单个复杂的 api 网关可能存在风险,并成为您架构的瓶颈。 较大的系统通常通过对客户端类型(如移动、Web 和桌面功能)进行分组来公开多个 API 网关。 当您想避免为多个接口定制单个后端时,BFF 模式很有用。
所以我们应该根据用户界面创建几个 api 网关。
这些 api 网关提供最匹配前端环境的需求,而无需担心影响其他前端应用程序。
Backend for Frontends 模式为实现多个网关提供了方向。


为前端模式 BFF 设计后端 — 微服务通信设计模式


我们将根据后端模式 BFF 添加更多 API 网关模式来迭代我们的电子商务架构。

msa

如您所见,我们在应用程序中添加了多个 API 网关。 这些 api 网关提供最匹配前端环境的需求,而无需担心影响其他前端应用程序。 Backend for Frontends 模式为实现多个网关提供了方向。


后端内部微服务之间的服务到服务通信——微服务通信设计模式

 


好的,我们已经在我们的微服务架构中创建了 API Gws。 并表示所有这些同步请求都来自客户端,并通过 api gws 进入内部微服务。
但是,如果客户端请求需要访问多个内部微服务怎么办? 我们如何管理内部微服务通信?

msa

在设计微服务应用程序时,我们应该注意后端内部微服务如何相互通信。最佳实践是尽可能减少服务间通信。
但是,在某些情况下,由于客户要求或请求的操作需要访问多个内部服务,我们无法减少这些内部通信。
例如,查看图像并考虑用例:

  • 用户想要结帐购物车并创建订单

那么我们如何实现这个请求呢?
所以这些内部调用使每个微服务耦合,在我们的例子中 sc - Product 和 Pricing 微服务是相互依赖和耦合的。
如果其中一个微服务出现故障,它就无法向客户端返回数据,因此它没有任何容错能力。如果微服务的依赖和耦合增加,那么就会产生很多问题,并且会削弱微服务架构的力量。
如果客户端结帐购物车,这将启动一组操作。
因此,如果我们尝试使用请求/响应同步消息模式来执行这个订单用例,那么它看起来就像这个图像。
如您所见,一个客户端 http 请求有 6 个同步 http 请求。
因此很明显,增加延迟并对我们系统的性能、可扩展性和可用性产生负面影响。
如果我们有这个用例,如果第 5 步或第 6 步失败了怎么办,或者如果某个中间服务宕机了怎么办?
即使没有宕机,也可能是一些服务繁忙,无法及时响应,导致不可接受的高延迟。
那么这种需求的解决方案是什么?
我们可以应用 2 种方法来解决这个问题,
1- 将微服务通信更改为与消息代理系统的异步方式,我们将在下一节中看到这一点。
2- 使用服务聚合器模式在 1 个 api gw 中聚合一些查询操作。


服务聚合器模式——微服务通信设计模式


为了最小化服务到服务的通信,我们可以应用服务聚合器模式。基本上,服务聚合器设计模式是接收来自客户端或 api gw 的请求,然后分派多个内部后端微服务的请求,然后将结果组合并在 1 个响应结构中响应发起请求。

msa

通过服务聚合器模式实现,我们可以减少客户端和微服务之间的聊天和通信开销


设计——服务聚合器模式——服务注册模式——微服务通信设计模式


在本节中,我们将通过添加服务聚合器模式 - 服务注册表模式 - 微服务通信设计模式来迭代我们的电子商务架构。

msa

正如你所看到的,我们已经为我们的电子商务架构应用了服务聚合器模式——服务注册模式。


微服务基于消息的异步通信


如果您的通信仅在几个微服务之间进行,则同步通信是好的。 但是当涉及到几个微服务需要相互调用并等待一些长时间的操作直到完成时,我们应该使用异步通信。

msa

否则,微服务的依赖和耦合将造成瓶颈并造成架构的严重问题。
如果你有多个微服务需要相互交互
如果你想在没有任何依赖或松耦合的情况下与它们交互,那么我们应该在微服务架构中使用基于异步消息的通信。
因为基于异步消息的通信提供了事件处理。 所以事件可以放置微服务之间的通信。
我们称这种通信为事件驱动的通信。


发布-订阅设计模式


发布-订阅是一种消息传递模式,有消息的发送者称为发布者,有特定的接收者称为订阅者。

msa

所以发布者不会将消息直接发送给订阅者。
相反,对已发布的消息进行分类并将它们发送到消息代理系统,而不知道那里有哪些订阅者。
类似地,订阅者表示感兴趣并且只接收感兴趣的消息,而不知道哪些发布者发送给他们。


设计——发布/订阅消息代理——微服务异步通信设计模式


在本节中,我们将通过添加 Pub/Sub 消息代理来迭代我们的电子商务架构,以提供微服务异步通信设计。

msa

 

如您所见,我们已经应用了 Pub/Sub Message Broker — 微服务异步通信设计模式。
如果我们调整技术堆栈,我们基本上从 Pub/Sub 消息代理的选项开始。您可以选择 2 个不错的选择;


1- Kafka
2- RabbitMQ


微服务数据管理


在单体架构中,查询不同的实体非常好,因为单个数据库保持数据管理也很简单。跨多个表查询数据很简单。对数据的任何更改都会一起更新或全部回滚。严格一致性的关系型数据库具有ACID事务保证,便于管理和查询数据。
但是在微服务架构中,当我们使用“多语言持久性”时
这意味着每个微服务都有不同的数据库,包括关系数据库和无 sql 数据库,我们应该在执行用户交互时设置策略来管理这些数据。
这意味着我们在处理微服务之间的数据交互时有几种模式和实践,我们将在本节中学习这些模式和原则。
微服务是独立的,只执行特定的功能需求,对于我们在电子商务应用程序中的案例,我们有产品、购物篮、折扣、订购微服务需要相互交互以执行客户用例。这意味着他们需要经常相互整合。大多数这些集成是查询每个服务数据以进行聚合或执行逻辑。


CQRS 设计模式


CQRS 是微服务间查询的重要模式之一。我们可以使用 CQRS 设计模式来避免复杂的查询来摆脱低效的连接。 CQRS 代表命令和查询责任分离。基本上,这种模式将数据库的读取和更新操作分开。
为了隔离命令和查询,其最佳实践是将读写数据库与 2 个数据库物理分离。通过这种方式,如果我们的应用程序是读密集型的,这意味着读多于写,我们可以定义自定义数据模式以优化查询。

msa

物化视图模式是实现读取数据库的好例子。
因为通过这种方式,我们可以避免使用预定义的细粒度数据进行复杂的连接和映射以进行查询操作。
通过这种隔离,我们甚至可以使用不同的数据库来读取和写入数据库类型,例如使用 no-sql 文档数据库进行读取和使用关系数据库进行 crud 操作。


事件溯源模式


我们已经学习了 CQRS 模式,并且 CQRS 模式主要与 Event Sourcing 模式一起使用。 当使用带有事件溯源模式的 CQRS 时,主要思想是将事件存储到写入数据库中,这将是真实事件数据库的来源。
之后,CQRS 设计模式的读取数据库提供具有非规范化表的数据的物化视图。 当然,这个物化视图读取数据库消耗来自写入数据库的事件并将它们转换为非规范化视图。

msa

随着事件溯源模式的应用,它正在改变为将数据保存到数据库中的操作。 事件溯源模式不是将数据的最新状态保存到数据库中,而是提供将所有事件按顺序排列的数据事件保存到数据库中。 这个事件数据库称为事件存储。
它不会更新数据记录的状态,而是将每个更改附加到事件的顺序列表中。 因此,事件存储成为数据的真实来源。 之后,这些事件存储转换为遵循物化视图模式的读取数据库。 此转换操作可以通过带有消息代理系统的发布事件的发布/订阅模式来处理。


设计架构——CQRS、事件溯源、最终一致性、物化视图


我们将通过应用 CQRS、事件溯源、最终一致性、物化视图来设计我们的电子商务架构。

msa

因此,当用户创建或更新订单时,我将使用关系写入数据库,当用户查询订单或订单历史时,我将使用 no-sql 读取数据库,并在使用消息代理系统同步 2 个数据库时使它们保持一致应用发布/订阅模式。
现在我们可以考虑这些数据库的技术栈,我将使用 SQL Server 进行关系写入数据库,使用 Cassandra 进行无 SQL 读取数据库。当然,我们将使用 Kafka 将这 2 个数据库与 pub/sub Kafka 主题交换同步。
如您所见,我们已经完成了微服务数据库模式的设计。让我们深入了解微服务中的这些事件驱动架构。


事件驱动的微服务架构


基本上事件驱动的微服务架构是指通过事件消息与微服务进行通信。我们在微服务异步通信部分的发布/订阅模式和 Kafka 消息代理系统中看到了这一点。
我们说过,使用事件驱动架构,我们可以进行异步行为和松散耦合的结构。例如,服务不是在需要数据时发送请求,而是通过事件使用它们。这将提供性能提升。

msa

但在事件驱动的微服务架构上也有巨大的创新,例如使用实时消息传递平台、流处理、事件中心、实时处理、批处理、数据智能等。
因此,我们可以使这种事件驱动的方法更通用,并随着这种架构的发展而具有实时事件处理功能。
根据这种新的事件驱动微服务架构,每件事都是通过 Event-Hubs 进行通信。 我们可以认为 Event-Hubs 是一个可以进行实时处理的大型事件存储数据库。


设计架构——事件驱动的微服务架构


我们将使用事件驱动的微服务架构来设计我们的电子商务应用程序。

msa

现在让我们决定在这个架构中使用技术栈。 当然,我们应该选择 Apache Kafka——作为事件中心和 Apache Spark,用于转换或响应数据流的实时和近实时流应用程序。
正如你所看到的,现在我们有了事件驱动微服务架构的反应式设计。
现在我们可以问同样的问题;


多少并发请求可以容纳我们的设计?

msa

借助这种最新的事件驱动微服务架构,它使用容器和编排器进行部署,可以以低延迟满足目标并发请求。
因为该架构是完全松散耦合的,并且设计用于高可扩展性和高可用性。
如您所见,我们设计的电子商务微服务架构具有设计原则和模式的各个方面。 现在,您可以通过这些学习准备设计自己的架构,并知道如何在您的设计中使用这些模式工具箱。


带课程的逐步设计架构

我刚刚发布了一门新课程——使用模式和原则设计微服务架构。
在本课程中,我们将学习如何使用设计模式、原则和最佳实践来设计微服务架构。 我们将从设计单体到事件驱动的微服务开始,并一起使用正确的架构设计模式和技术。

原文:https://medium.com/design-microservices-architecture-with-patterns/monolithic-to-microservices-architecture-with-patterns-best-practices-a768272797b2

本文:https://jiagoushi.pro/node/1863