微服务可以对您的企业产生积极影响。 因此,值得一提的是,如何处理微服务架构(MSA)和一些微服务设计模式。 微服务架构的一般目标或原则。 这是微服务架构方法[1]中要考虑的四个目标。

· 降低成本:MSA将降低设计,实施和维护IT服务的总体成本。

· 提高发布速度:MSA将提高从构思到服务部署的速度。

· 增强弹性:MSA将提高我们服务网络的弹性。

· 启用可见性:MSA支持可在您的服务和网络上提供更好的可见性。

您需要了解微服务架构的构建原理

· 可扩展性

· 可用性

· 弹性

· 灵活性

· 独立自主

· 分散治理

· 故障隔离

· 自动配置

· 通过DevOps持续交付

聆听上述原则,在使您的解决方案或系统付诸实践的同时,带来了一些挑战和问题。 这些问题在许多解决方案中都很常见。 使用正确和匹配的设计模式可以克服这些问题。 微服务有一些设计模式,可以分为五种模式。 每个都包含许多模式。 下图显示了那些。

微服务架构设计和思考(微服务的架构和设计模式)(1)

> Design Patterns for Microservices

分解模式

按业务能力分解

微服务就是要使用单一责任原则使服务松散耦合。 它根据业务能力分解。 定义与业务能力相对应的服务。 业务能力是来自业务体系结构建模的概念[2]。 企业为了创造价值而要做的事情。 业务能力通常对应于一个业务对象,例如

· 订单管理负责订单

· 客户管理对客户负责

按子域分解

使用业务功能分解应用程序可能是一个不错的开始,但是您会遇到所谓的"神类",这很难分解。 这些类将在多种服务中通用。 定义与域驱动设计(DDD)子域相对应的服务。 DDD将应用程序的问题空间(业务)称为域。 域由多个子域组成。 每个子域对应于业务的不同部分。

子域可以分类如下:

· 核心-业务和应用程序最有价值部分的关键区别

· 支持-与业务有关,但与众不同。 这些可以在内部实现,也可以外包

· 通用-不特定于业务,理想情况下使用现成的软件实施

订单管理的子域包括:

· 产品目录服务

· 库存管理服务

· 订单管理服务

· 送货管理服务

按事务分解/两阶段提交(2pc)模式

您可以通过事务分解服务。 然后,系统中将有多个事务。 分布式事务处理的重要参与者之一是事务处理协调器[3]。 分布式事务包括两个步骤:

· 准备阶段-在此阶段,事务的所有参与者都准备提交并通知协调员他们已准备好完成事务

· 提交或回滚阶段-在此阶段,事务协调器向所有参与者发出提交或回滚命令

2PC的问题在于,与单个微服务的运行时间相比,它相当慢。 即使微服务在同一网络上,它们之间的事务协调也确实会降低系统速度,因此这种方法通常在高负载情况下不常用。

扼杀模式

在上面的三种模式中,您经历的设计模式是分解Greenfield的应用程序,但是您所做的工作中有80%是针对Brownfield应用程序,这是大型的整体应用程序(旧版代码库)。 扼杀者模式可以解决。 这将创建两个单独的应用程序,它们在同一URI空间中并排运行。 随着时间的推移,新重构的应用程序会"扼杀"或替换原始应用程序,直到最终,您可以关闭整体应用程序。 Strangler应用程序步骤可以转换,共存和消除[4]:

· 转换-使用现代方法创建并行的新站点。

· 消除-从现有站点中删除旧功能。

隔板模式

将应用程序的元素隔离到池中,以便如果其中一个失败,其他应用程序将继续运行。 这种模式之所以称为"舱壁",是因为它类似于船体的分段分区。 根据使用者负载和可用性要求,将服务实例划分为不同的组。 此设计有助于隔离故障,并允许您即使在故障期间仍可为某些使用者维持服务功能。

边车模式

将应用程序的组件部署到单独的处理器容器中以提供隔离和封装。 这种模式还可以使应用程序由异构组件和技术组成。 该模式被称为Sidecar,因为它类似于连接到摩托车的Sidecar。 在该模式中,sidecar附加到父应用程序,并为该应用程序提供支持功能。 Sidecar还与父应用程序共享相同的生命周期,并与父应用程序一起创建并退出。 Sidecar模式有时被称为sidekick模式,是我们在文章中显示的最后一个分解模式。

整合模式

API网关模式

当应用程序分解为较小的微服务时,有一些需要解决的问题

· 不同的渠道多次呼吁提供多种微服务

· 需要处理不同类型的协议

· 不同的消费者可能需要不同的响应格式

API网关有助于解决微服务实现引发的许多问题,而不仅限于上述问题。

· API网关是任何微服务调用的单一入口点。

· 它可以用作将请求路由到相关微服务的代理服务。

· 它可以汇总结果以发送回消费者。

· 该解决方案可以为每种特定类型的客户端创建一个细粒度的API。

· 它还可以转换协议请求并做出响应。

· 它还可以减轻微服务的身份验证/授权责任。

聚合模式

在将业务功能分解为几个较小的逻辑代码段时,有必要考虑如何对每个服务返回的数据进行协作。 消费者不能承担这种责任。 聚合器模式有助于解决此问题。 它讨论了我们如何聚合来自不同服务的数据,然后将最终响应发送给消费者。 这可以通过两种方法来完成[6]:

· 复合微服务将调用所有必需的微服务,合并数据,并在发送回数据之前对其进行转换。

· API网关还可以将请求划分为多个微服务,并在将数据发送给使用者之前汇总数据。

如果要应用任何业务逻辑,建议选择复合微服务。 否则,API网关是已建立的解决方案。

代理模式

API网关我们只是通过API网关公开微服务。 我允许获得API功能,例如GW中的安全性和API分类。 在此示例中,API网关具有三个API模块:

· 移动API,为FTGO移动客户端实现API

· 浏览器API,它实现了浏览器中运行的JavaScript应用程序的API

· 公共API,为第三方开发人员实现API

网关路由模式

API网关负责请求路由。 API网关通过将请求路由到相应的服务来实现一些API操作。 当API网关接收到请求时,它会查询路由映射,该路由映射指定将请求路由到的服务。 路由映射例如可以将HTTP方法和路径映射到服务的HTTP URL。 此功能与Web服务器(如NGINX)提供的反向代理功能相同。

链式微服务模式

单个服务或微服务将有多个依赖关系,例如:销售微服务具有依赖产品微服务和订单微服务。 链接微服务设计模式将帮助您根据请求提供合并结果。 微服务1接收到的请求,该服务随后与微服务2进行通信,并且可能正在与微服务3进行通信。 所有这些服务都是同步调用。

分支模式

微服务可能需要从包括其他微服务在内的多个来源获取数据。 分支微服务模式是聚合器和链设计模式的混合,并允许来自两个或多个微服务的同时请求/响应处理。 调用的微服务可以是微服务链。 Brach模式还可用于根据您的业务需求调用不同的微服务链或单个链。

客户端UI组合模式

当通过分解业务功能/子域来开发服务时,负责用户体验的服务必须从多个微服务中提取数据。 在单片世界中,从UI到后端服务只有一次调用,以检索所有数据并刷新/提交UI页面。 但是,现在不一样了。 对于微服务,必须将UI设计为具有屏幕/页面的多个部分/区域的框架。 每个部分都将调用单个后端微服务以提取数据。 诸如AngularJS和ReactJS之类的框架可以轻松地做到这一点。 这些屏幕称为单页应用程序(SPA)。 每个团队都开发一个客户端UI组件,例如AngularJS指令,该组件实现其服务的页面/屏幕区域。 UI团队负责通过构成多个服务特定的UI组件来实现构建页面/屏幕的页面框架。

数据库模式

为微服务定义数据库架构时,我们需要考虑以下几点。

· 服务必须是松散耦合的。 它们可以独立开发,部署和扩展。

· 商业交易可能会强制跨越多个服务的不变量。

· 一些业务交易需要查询多个服务拥有的数据。

· 有时必须复制和共享数据库才能进行扩展。

· 不同的服务有不同的数据存储要求。

每个服务的数据库

为了解决上述问题,必须为每个微服务设计一个数据库。 它必须仅对该服务专用。 只能由微服务API访问它。 其他服务无法直接访问它。 例如,对于关系数据库,我们可以使用每个服务专用表,每个服务架构或每个服务数据库服务器。

每个服务共享数据库

我们已经讨论了每个服务一个数据库是微服务的理想选择。 它是微服务的反模式。 但是,如果应用程序是一个整体并且试图闯入微服务,那么非规范化就不那么容易了。 在后面的阶段中,我们可以转到每个服务模式的数据库,直到我们遵循此模式。每个服务的共享数据库并不理想,但这是上述情况的可行解决方案。 多数人认为这是微服务的反模式,但对于棕地应用程序,这是将应用程序分解成较小逻辑部分的一个很好的开始。 这不应应用于未开发的应用程序。

命令查询责任隔离(CQRS)

一旦我们实现了每个服务的数据库,就需要查询,这需要来自多个服务的联合数据。 这是不可能的。 CQRS建议将应用程序分为两部分-命令端和查询端。

· 命令行处理创建,更新和删除请求

· 查询端通过使用实例化视图来处理查询部分

通常将事件源模式与它一起使用来为任何数据更改创建事件。 通过订阅事件流,可以使物化视图保持更新。

活动采购

大多数应用程序都使用数据,典型的方法是使应用程序保持当前状态。 例如,在传统的创建,读取,更新和删除(CRUD)模型中,典型的数据处理是从存储中读取数据。 它包含经常使用事务锁定数据的限制。

Event Sourcing模式[8]定义了一种方法,用于处理由一系列事件驱动的数据上的操作,每个事件都记录在仅追加存储中。 应用程序代码向事件存储发送一系列事件,这些事件命令性地描述了对数据执行的每个操作,并在事件存储中保留了这些事件。 每个事件代表一组数据更改(例如,AddedItemToOrder)。

这些事件将保留在充当记录系统的事件存储中。 事件存储发布的事件的典型用途是在应用程序中的动作更改实体时维护实体的实体化视图,以及与外部系统集成。 例如,系统可以维护用于填充UI部分的所有客户订单的实例化视图。 当应用程序添加新订单,添加或删除订单上的项目以及添加运输信息时,可以处理描述这些更改的事件并将其用于更新实例化视图。 该图显示了该模式的概述。

微服务架构设计和思考(微服务的架构和设计模式)(2)

> Event Sourcing pattern[8]

传奇模式

当每个服务都有自己的数据库并且一个业务事务跨越多个服务时,我们如何确保各个服务之间的数据一致性。 每个请求都有一个补偿请求,该请求将在请求失败时执行。 它可以通过两种方式实现:

· 编排-在没有中央协调的情况下,每个服务都会生成并侦听另一个服务的事件,并决定是否应该采取措施。 编排是指定两个或两个以上参与者的方式。 任何一方都无法控制对方的流程,或者对这些流程的任何可见性,都无法协调他们的活动和流程以共享信息和价值。 当需要跨控制/可见性域进行协调时,请使用编排。 您可以在简单的情况下将编排视为网络协议。 它规定了各方之间可接受的请求和响应模式。

微服务架构设计和思考(微服务的架构和设计模式)(3)

> Saga pattern — Choreography

· 编排-编排(对象)负责传奇的决策和业务逻辑排序。 当您控制流程中的所有参与者时。 当它们全部处于一个控制范围内时,您可以控制活动的流程。 当然,这通常是当您指定将在您拥有控制权的一个组织内制定的业务流程时。

微服务架构设计和思考(微服务的架构和设计模式)(4)

> Sage pattern — Orchestration

可观察性模式

日志汇总

考虑一个应用程序包含多个服务的用例。 请求通常跨越多个服务实例。 每个服务实例均以标准化格式生成日志文件。 我们需要一个集中式日志记录服务,该服务可以汇总每个服务实例的日志。 用户可以搜索和分析日志。 他们可以配置在某些消息出现在日志中时触发的警报。 例如,PCF确实有Log Aggregator,它从PCF平台的每个组件(路由器,控制器,diego等)收集日志,并附带应用程序。 AWS Cloud Watch也这样做。

性能指标

当服务组合由于微服务体系结构而增加时,密切注意事务,以便可以监控模式并在发生问题时发送警报就变得至关重要。

需要度量服务来收集有关单个操作的统计信息。 它应该聚合提供报告和警报的应用程序服务的指标。 有两种用于汇总指标的模型:

· 推送-服务将指标推送到指标服务,例如 NewRelic,AppDynamics

· 提取-指标服务从服务中提取指标,例如 普罗米修斯

分布式跟踪

在微服务架构中,请求通常跨越多个服务。 每个服务通过跨多个服务执行一个或多个操作来处理请求。 在进行故障排除时,值得拥有跟踪ID,但我们会端对端跟踪请求。

解决方案是引入一个事务ID。 可以采用跟随方式;

· 为每个外部请求分配一个唯一的外部请求ID。

· 将外部请求ID传递给所有服务。

· 在所有日志消息中包括外部请求ID。

健康检查

实施微服务架构后,服务可能会启动但无法处理事务。 每个服务都需要具有一个可用于检查应用程序运行状况的终结点,例如/ health。 该API应该o检查主机的状态,与其他服务/基础结构的连接以及任何特定的逻辑。

交叉切割关注模式

外部配置

服务通常还会调用其他服务和数据库。 对于开发,质量检查,UAT,产品等每个环境,端点URL或某些配置属性可能会有所不同。 这些属性中的任何一项更改都可能需要重新构建和重新部署服务。

为了避免代码修改,可以使用配置。 外部化所有配置,包括端点URL和凭据。 应用程序应该在启动时或运行时加载它们。 这些可以在启动时由应用程序访问,也可以在不重新启动服务器的情况下进行刷新。

服务发现模式

当微服务出现时,我们需要在调用服务方面解决一些问题。

使用容器技术,IP地址可以动态分配给服务实例。 每次地址更改时,消费者服务都会中断,需要手动更改。

消费者必须记住每个服务URL,并使其紧密耦合。

需要创建服务注册表,该注册表将保留每个生产者服务的元数据和每个规范的规范。 服务实例在启动时应注册到注册表,而在关闭时应注销。 服务发现有两种类型:

· 客户端:例如:Netflix Eureka

· 服务器端:例如:AWS ALB。

微服务架构设计和思考(微服务的架构和设计模式)(5)

> service discovery [9]

断路器模式

一个服务通常会调用其他服务来检索数据,并且下游服务可能会关闭。 这样做有两个问题:首先,请求将继续进入服务中断状态,耗尽网络资源,并降低性能。 其次,用户体验将是糟糕且不可预测的。

消费者应通过代理来调用远程服务,该代理的行为与断路器相似。 当连续的故障数超过阈值时,断路器将跳闸,并且在超时期间内,所有调用远程服务的尝试都将立即失败。 超时到期后,断路器将允许有限数量的测试请求通过。 如果这些请求成功,则断路器将恢复正常操作。 否则,如果发生故障,则超时时间将再次开始。 如果此操作很有可能失败,则此模式适用于防止应用程序尝试调用远程服务或访问共享资源。

微服务架构设计和思考(微服务的架构和设计模式)(6)

> Circuit Breaker Pattern [10]

蓝绿色部署模式

使用微服务架构,一个应用程序可以具有许多微服务。 如果我们停止所有服务,然后部署增强版本,则停机时间将是巨大的,并可能影响业务。 同样,回滚将是一场噩梦。 蓝绿色部署模式可避免这种情况。

可以实施蓝绿色部署策略以减少或消除停机时间。 它通过运行两个相同的生产环境Blue和Green来实现这一目标。 假设绿色是现有的活动实例,蓝色是该应用程序的新版本。 在任何时候,只有一个环境处于活动状态,该活动环境为所有生产流量提供服务。 所有云平台均提供用于实施蓝绿色部署的选项。

微服务架构设计和思考(微服务的架构和设计模式)(7)

> Blue-Green Deployment Pattern

参考文献[1]"微服务体系结构:原则,实践和文化的统一",作者Irakli Nadareishvili,Matt McLarty和Michael Amundsen

[2] https://microservices.io/patterns/decomposition/decompose-by-business-capability.html

[3] https://www.baeldung.com/transactions-across-microservices

[4] https://developer.ibm.com/articles/cl-strangler-application-pattern-microservices-apps-trs/

[5] https://docs.microsoft.com/zh-CN/azure/architecture/patterns/bulkhead

[6] https://dzone.com/articles/design-patterns-for-microservices

[7] https://docs.microsoft.com/zh-CN/azure/architecture/patterns/cqrs#event-sourcing-and-cqrs

[8] https://docs.microsoft.com/zh-CN/azure/architecture/patterns/event-sourcing

[9] https://www.dineshonjava.com/microservices-with-spring-boot/

[10] https://docs.microsoft.com/zh-CN/azure/architecture/patterns/circuit-breaker

(本文翻译自madhuka udantha的文章《Microservice Architecture and Design Patterns for Microservices》,参考:https://medium.com/@madhukaudantha/microservice-architecture-and-design-patterns-for-microservices-e0e5013fd58a)

,