vlambda博客
学习文章列表

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

Microservices Patterns

模式是可以以可预测的方式定期重复的东西。

这个概念适用于所有环境——在建筑、设计、IT 以及需要做某事的每个环境中。

模式的概念始于 70 年代后期,涉及建筑和建筑设计,但模式一直存在。例如,看看大自然——it 充满了可重复和可预测的模式。它们出现在螺旋、波浪和花椰菜中,以及对称几何、分形等数学中。

然而,在我们的环境(IT 环境)中,我们首先在 90 年代中期在我读过的一本书中发现了模式。

模式语言不断演进,以跟上 IT 演进和革命的速度,在新千年伊始,新的工具和系统层出不穷。互联网正在爆炸式增长,分布式系统随着新的基础设施、新架构和新模式的出现而上市。

在我们开始之前,值得一提的是,微服务架构是单体架构的替代方案,因为每种架构都有自己的优点和缺点——这都是关于权衡的。

旧的原则和模式,例如来自 SOA 的服务发现和路由,仍然有效,并且在单体和微服务架构上都在使用。然而,随着微服务和容器的出现,设计、实施和部署软件的方法发生了巨大变化。应用程序现在针对灵活性、可扩展性、故障、弹性进行了优化,并能快速适应新的请求和业务。在新原则的推动下,这些新架构需要应用一组不同的模式和实践。

在本章中,我们不会访问和描述与微服务方法一起使用的模式的完整列表,但我们将专注于最常用的模式,以帮助您开始并对模式主题感兴趣。有大量关于模式的书籍,如果您关心云环境,您应该阅读 Packt 的 Java EE 8 设计模式和最佳实践https://www.packtpub.com/application-development/java-ee-8-design -模式和最佳实践)。

本章将介绍的模式如下:

  • Decomposition
  • API gateway
  • Bulkheads
  • Circuit breaker
  • Sidecar

Decomposition

分解并不是最好的词——它让人想起坏事。但是,在这种情况下,这意味着拆分一个服务,例如我们的足球经理应用程序;即按照单一职责原则(SRP)将其拆分为不同的微服务并解耦组件。 SRP 依赖于这样一个事实,即一个组件只做一件事,而且做得非常好。下图为我们提供了关于分解的概念:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

在我们的示例中,整个应用程序可以设计和部署为一个整体,我们将所有部分组合在一起。当然,它会运作良好,但有很多缺点(灵活性、可扩展性、失败、弹性等)。

How do you decompose an application?

这样的问题没有真正的答案——像往常一样,这取决于什么最适合微服务架构的治理、所涉及的团队、当前的基础设施和成本控制。有很多方面需要考虑,并且没有一刀切的解决方案。

By functionality

应用程序可以按功能分解,即从应用程序中取出每个功能并将其转换为微服务。为了能够遵循这种繁琐的方法,需要对核心组件有完整而深入的了解。不要忘记单体应用程序可能没有一个单一的集成点;相反,集成点可以分布在整个源代码中。

By integration

应用程序可以通过其集成点或它与其他组件和子组件的通信方式进行分解。在这里,更多的组件可以合并在一起。在这种方法中要考虑的另一个方面是最终只将那些非常慢的组件与处理请求速度较快的组件分开。此外,合并交互缓慢的组件。

By resource consumption

应用程序可以按其资源消耗级别进行分解。可以隔离贪婪组件以增加控制并减少资源收获。只喂那些贪吃的。

如果部署在微服务架构中,所有上述方法都会导致灵活且可扩展的系统。但是,考虑服务或微服务的功能并不总是正确的选择。如今,微服务的部署出现了新的趋势(如果它们真的很小,我们可能应该称它们为纳米服务),这就是所谓的无服务器部署。

Serverless

这种解决方案背后的想法是考虑调用服务的频率/时间。例如,假设您有一家商店,并且在复活节和圣诞节假期期间有特别折扣。一直激活特别折扣服务是没有意义的,因为它会导致金钱损失。如果有一个基础设施可以在其他服务请求时按需部署您的服务,那就太好了。这是少服务器的要点,它可以很好地处理微服务和云环境。大型云厂商提供了这些新技术,其中一些如下:

  • AWS Lambda
  • Google Cloud Functions
  • Azure Functions

API gateway

API 网关是一种服务,负责将请求从客户端路由到应用程序,与面向对象设计中称为 facade 的设计模式非常相似,这本书在 中有最好的描述Java EE 8 设计模式和最佳实践。

API 网关封装逻辑以调用适当的后端服务。由于它是单一入口点,它还可以具有其他功能,例如保护服务、转换有效负载、监控、限制、缓存和评估每个服务的请求数量等。 API 网关还负责公开具有不同协议的服务。

另一个可以使用的场景是调用多个服务,聚合结果,返回正确的输出(API组合实现),如下图所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

Bulkhead

这种模式被命名为舱壁,因为它充当船舶的隔板以防止船舶沉没。它基本上隔离了船舶的各个隔间,以避免或最小化风险沉没。

这同样适用于软件,其中一次故障不会危及整个系统。在 IT 中,特别是在实现数据访问层时,应将隔板模式用于连接池。数据库或具有单个连接池的 HTTP 连接都可能危及整个系统。假设你的代码没有正确释放连接——连接池很快就会充满活动连接,在这种情况下,通过 HTTP 连接处理数据库或其他服务的服务将无法正常运行,即使它们必须处理用不同的资源。

下图描述了依赖同一个连接池的各种应用程序。突然之间,一个应用程序中的一个错误使连接池饱和。结果是池中的连接都被一个应用程序锁定,其他应用程序无法使用它:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

相反,通过为每个服务创建一个连接池,它可以避免整个系统因故障而失败,而只会损害一项功能,如下图所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

在我们的足球经理 应用程序 中,我们为每项服务指定了池,并且我们还为每项服务使用了不同的数据库,以实际表明您可以依赖不同的工具来完成正确的工作——同质性不再是强制性的使用微服务和提供异构运行时的 PaaS。

隔板模式无疑是一种好方法,但有时您的系统仍需要为该功能提供某种最低限度的功能。在这种情况下,断路器就是您需要的模式。

Circuit breaker

顾名思义,这种模式之所以这样命名,是因为它来自电子电路上下文。

听起来很熟悉,不是吗?

断路器模式的目的与隔板相同,但方法不同。同样,一个服务调用另一个没有响应或非常慢的服务可能会降低整个系统的性能。

实施断路器还有另一个原因,即避免不得不继续调用您已经知道已损坏或无法访问的服务。

假设服务 A 正在调用服务 B,而服务 B 已关闭 - 服务 A 应阻止此类集成并以超时错误或缓存数据进行响应。从电子上讲,这是电路中的open状态,即两点之间不再有联系。

断路器实现应定期轮询服务 B 以检查其健康状况。一旦服务 B 再次启动,断路器应该重置流程,让服务 A 再次调用服务 B。从电子上讲,这是电路中的close 状态。

断路器检查集成点的方式取决于用例。在一定数量的调用出错后,它可能会暂停服务 B。如果是这样,最好等待并重试。

Netflix Hystrix 给出了最著名的断路器实现。但是,这个库没有更积极的开发并且处于维护模式。当然,还有 Netflix Hystrix 的替代品,例如 Resilience4j、Sentinel 和 Istio。

后者是 OpenShift 使用的。Red Hat 支持的 PaaS,我们将在下一节中描述它。

Istio

以下是其网站 https://istio.io/ 中对 Istio 的定义:

"Istio addresses the challenges developers and operators face as monolithic applications transition toward a distributed microservice architecture."

随着微服务架构复杂性的增加,必须依赖弹性模式,例如断路、负载均衡、节流等。

Istio 通过 Envoy 代理使用可插拔策略实现所有这些行为模式,可以针对手头的特定用例/策略进行配置。这是一个例子:

metadata:
name: circuit-breaker-policy
namespace: default
spec:
destination:
name: circuit-breaker
labels:
version: v1
circuitBreaker:
simple-circuit-breaker:
maxConnections: 100
httpMaxRequests: 1000
httpMaxRequestsPerConnection: 10
httpConsecutiveErrors: 7
sleepWindow: 15m
httpDetectionInterval: 5m

这意味着服务网格在应用程序级别(在网络术语中,L7)上起作用,从而实现重试、超时、断路器、隔板和路由控制。

Sidecar

当我们说边车这个词时,首先想到的是摩托车上的飞行员,他的副驾驶位于摩托车本身的一个小胶囊中。

同样的建议也适用于软件。假设您有一个附加了一个组件的应用程序。但是,在软件环境中,sidecar 是一个可以从主应用程序中插入和拔出的组件,因为它必须是隔离的,并且在应用程序开始出现异常时不会影响应用程序。这将是应用程序的抵押品。 Sidecar 最常用的场景是监控、日志记录、指标等。

Sidecar 容器应该是可配置的,以便可以插入到任何应用程序中——它也不必只是单个应用程序。 Sidecar 的最佳匹配是容器。应用程序容器可以绑定到 sidecar 容器并作为容器组运行,这些容器组在 Kubernetes 和 OpenShift 世界中称为 pod。

几十年来,sidecar 模式的主要实现之一涉及代理,例如监控应用程序内存、健康检查和 CPU 使用率的代理。

如今,最流行的 Sidecar 实现是 Istio,它为您的服务部署了一个代理作为 Sidecar。对服务的所有请求都转到代理——Envoy 代理,它使用其配置来设置请求应该如何以及何时到达您的服务的策略。

Envoy 代理的示意图如下所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》微服务模式

使用 Istio,控制服务和服务网格非常容易。流量监控、访问控制、发现、安全、弹性、跟踪、断路器、路由、负载平衡、故障注入、重试、超时、镜像和速率限制等任何功能都可以在不触及原始应用程序的情况下添加,无论运行时环境和实现它的编程语言。

最后,sidecar 模式非常有用,但在实现方面有一点开销。如果你正在运行一个小软件,添加一个 sidecar 可能太多了,而且有点太复杂了。

Summary

在本章中,我们介绍了实现微服务架构所需的基本模式。当然,还有更多的模式可以学习、学习、测试和使用,但要开始使用,到目前为止已经描述的那些就足够了。

在下一章中,我们将开始为我们的足球经理应用程序构建模板,我们将了解如何在 OKD 中部署整个系统。