vlambda博客
学习文章列表

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》云-本地应用程序

Cloud-Native Applications

近年来,我们听到了很多关于云的消息,但没有真正的意义。这只是一个流行词,每个人都争先恐后地获取一些 Amazon EC2 实例并在上面放置一些服务,只是为了传播这个词——它在云端; 我把它放在云端; 我们在云端

拥抱云不仅仅是在上面部署一些东西。在这个词的背后,有一个与新技术、创新或迁移(更糟糕的是,转型)无关的整个世界;这是关于一场革命。

这是基础设施、开发和部署方面的一场革命。团队方面的革命。

基础设施的关键点是自动化。一切都需要自动化——配置服务器、磁盘空间、内存、网络和资源——一切。
开发的关键是保持小——小块相互独立的软件;小型开发团队专注于一些需要过度沟通并尽快从失败的软件中接收反馈的任务。后者只有通过自动化才能实现——构建自动化、测试自动化和部署自动化。新的基础设施建立在自动化的概念之上。如果你不自动化,你就不可能有弹性、灵活、有弹性和容错。

进入云意味着改变你的工作习惯,改变公司来组织和构建它的 IT 部门。

您如何开始使用云原生应用程序?首先,必须对实际基础设施进行深入评估。集成边界、安全性、遗留系统、设备组件、流程以及业务和运营需求——所有这些方面都需要检查以发现弱点和优势。评估可以导致培训人员和创建新团队。

云原生应用程序是考虑到云架构的所有特征的应用程序。只有这样才能您开始最精彩的游戏——构建您的云原生应用程序。

构建云原生应用程序最常用的方法之一是微服务。微服务和云原生应用程序之间的区别在于,前者可以由任何基础设施提供,后者是相同的,但它考虑了云和分布式环境的所有方面,其中单个地方不能考虑。

回到云架构,除了自动化之外,拥有微服务的优势在于效率:

  • Auto-provisioning: Infrastructure as code
  • Auto-redundancy: Cloud-native applications are inherently resilient to failure
  • Auto-scaling: By constantly measuring your microservices, you can decide when it's appropriate to add more nodes (scale out)

交付微服务的一种常见方式是通过 Linux 容器。微服务架构和 Linux 容器相得益彰。每个微服务都必须是一个独立的单元——专用资源、CPU、内存和磁盘空间。想象一下在单个虚拟机 (VM) 或数十或数百个VM 上提供此类服务。这个过程需要相当长的时间,基础设施很快就会开始缺乏资源,短期内你的基础设施就不够用了——这将是浪费金钱、浪费时间、浪费资源.

从基础架构的角度来看,容器非常适合微服务的自包含单元方法非常好。容器是轻量级的、隔离的,并且可以在几秒内完成配置——实际上是几毫秒。

在本章中,我们将介绍以下主题:

  • Twelve-factor applications
  • Microservices
  • Runtime environments

Twelve-factor applications

尽管有云的特性,但有几个因素使应用程序成为云原生应用程序,这些因素可以在 十二要素应用程序 宣言中找到,可在 https://12factor.net/

让我们一一分析这十二个因素。

Code base

第一个因素与源代码、保存位置以及保存方式有关。代码中的每个更改都必须保存并跟踪到源代码存储库中。如今,有很多选择:GitLab、GitHub、Bitbucket、Stash 和旧的 SVN(这是一场革命,所以切换到 Git)。所有代码,包括基础设施即代码,都应该进行版本控制,每个版本都可能对应于某个环境中的部署。

长话短说,有一个源代码存储库,最好有一个开源和广泛采用的解决方案。

Dependencies

第二个因素与依赖管理工具有关。我熟悉 Java 环境,并且自从它第一次发布以来,我一直在使用 Maven 来显式声明和隔离依赖项。

Maven 将所有内容集中到一个名为 pom.xml 的文件中,您可以在其中指定要使用的库或框架以及确切的版本。 Maven 将通过从 Internet(Maven 存储库)下载您需要的 JAR 来编译和构建您的代码。尽管如此,仍然有很多适用于所有现代编程语言的依赖管理工具,例如 Ivy、Gradle、Gemfiles、Bundler 和 Godm。

长话短说,有一个依赖管理工具来确保构建的一致性。

Config

第三个因素与应用程序的配置有关。应用程序必须将其配置外部化,而不是随应用程序本身一起提供。随应用程序一起提供配置需要在不同环境之间更改应用程序包,从而破坏工件的完整性。

要完全不受环境影响,配置参数必须驻留在环境变量中。除了环境变量,还有一些工具可以提供更好的配置分布,比如 Consul 和 Vault(安全相关的设置,比如密码)。

长话短说,将配置与代码分开。

Backing services

第四个因素与您的应用程序使用的服务有关。这些支持服务可能是文件存储、数据库或邮件服务器。应用程序应该只引用对此类服务的需求,但让基础架构(新的革命性云基础架构)进行资源绑定。这种关注点分离有助于您的应用程序附加和分离到不同的支持服务,这要归功于第三个因素——无需重新部署应用程序。这也是我们将在第8章中描述的断路器模式的基础, 微服务模式

长话短说,将您的应用程序与资源集成,而不是实现。

Build, release, run

第五因素与第一、第二和第三因素有关。它是关于如何构建、发布(打包)一段代码并在目标执行环境中运行的。

前面的步骤称为阶段,代表应用程序的生命周期。每个阶段都有自己的特定角色,并且与任何其他阶段无关,所有这些阶段共同构成一个部署。

因此,要执行部署,我们需要以下内容:

  • We need to build our source code pulled from a repository by identifying the code and its version. This is done by fetching dependencies and compiling the code (the first and second factors).
  • To release the previous build, by identifying it by its name and version, we need to attach the appropriate configuration settings (the third factor). Every release has its own unique version (date, incrementing numbers, code name, and so on).
  • To run the released build into the execution environment, we need to launch a process that grabs the previous release, by identifying it through name and version.

这些阶段可以而且应该由云平台提供的工具来执行。 Jenkins 和 GitLab 持续集成 (CI) 等工具非常适合此类任务。更多细节可以在第 9 章 部署

长话短说,你构建的就是你发布的就是你运行的。

Processes

第六个因素与您的应用程序可能具有的状态有关。并且云原生应用程序必须是无状态的,以尊重可扩展性、灵活性、弹性和容错性等特性。

每个状态都必须保存、存储并保存到支持服务,例如存储或数据库,这些服务根据定义是有状态的。

长话短说,不要持有状态。

Port binding

第七个因素与端口绑定有关,即应用程序如何访问和公开。云原生应用程序不需要任何运行时,例如应用程序服务器或 Web 服务器;一切都是嵌入式的,它是自包含的,并通过最适合其集成功能的协议(HTTP、AMQP、MQTT、XMPP 等)通过端口公开其服务(例如 API)。

这也意味着,如果您公开您的应用程序,它可以成为另一个应用程序的支持服务。云基础设施将提供路由功能。

Concurrency

第八个因素与并发有关,即如何扩展以及如何运行同一云原生应用程序的多个实例以响应不断增加的工作负载。

根据运行时执行环境,云原生应用程序可以是运行以服务传入请求的 PHP、Ruby、Python 或 Java 进程。如今,前面提到的大多数技术都支持多线程,因此只要资源可用,它们就可以在内部分散工作负载。如果有足够的资源,扩大规模可能是一种解决方案,但只是暂时的。迟早,资源将再次丢失。云基础设施唯一有效的解决方案是向外扩展,Linux 容器(事实上的标准是 Docker)确实有助于解决这个问题。 您的应用程序可以运行新的 Linux 容器,并且可以处理更多工作负载。

Disposability

第九个因素与轻轻停止应用程序有关。应用程序可能因多种原因(新版本可用、更新、重新加载和重新启动)而关闭,十二因素应用程序必须能够优雅地处理关闭,这意味着无需完成正在运行的任务接受新的。一旦每项任务完成(中止或终止),应用程序将关闭。

这些功能是通过不同的框架提供的,可用于最常用的编程语言和运行时。

Development/production parity

第十个因素与运行时执行环境有关;更具体地说,使这些环境之间的差异尽可能小。

区别在于正在运行的版本,即正在运行的特定应用程序的版本。在生产中使用较旧的版本,在开发或用户验收测试 (UAT) 中使用较新的版本是很常见的。

但是云原生应用程序是在考虑新概念和想法的基础上构建的,以反映云平台,因此持续集成和持续交付的工具应该填补环境之间的空白。

还可以进行持续部署;这只是一个选择问题。将您的新版本带到环境中,直到预生产(持续交付)或将其带到生产(持续部署);这取决于组织及其业务模式。

Logs

第十一因素与应用程序日志有关。日志是应用程序本身之后的第一个重要的东西。没有日志,您的系统是盲目的,运营团队是盲目的,没有监控,您将无法修复一行代码,尤其是在云基础设施中。

在云环境中,在我们的革命中,日志也应该改变。运行时执行环境中的日志文件是一个有状态的组件。如果执行环境崩溃,日志就会消失。

代码中的任何事件都会生成一个日志条目,这应该流式传输到有状态的支持服务,该服务接收日志事件(来自不同的应用程序)并存储它们以供以后分析和聚合。有许多免费和开源工具可用于自省应用程序随时间的行为,例如 ELF、EFK 和 Grafana。

日志对于跟踪请求/响应事务的流程也非常重要,该事务可能会在返回给颁发者之前从服务反弹到服务。日志跟踪是云原生应用程序应该提供和遵循的一个重要方面。

您可能听说过遥测——您的事件流日志可能作为信息携带什么以及它如何携带它。监控是与应用程序性能相关的东西(也称为 APM);遥测是关于在特定时间从业务角度来看发生的事情(例如,哪些产品在午餐时间卖得最多)。

Admin processes

最后但同样重要的是,第十二个因素与运行管理任务方面的管理有关。

这些任务应该在运行时执行环境中运行,因此它们应该与应用程序本身一起提供,并且应该用于修复/补偿应用程序的迁移方面。假设您更改了域模型;这也应反映在数据库级别,因此应提供并执行一些更改数据库架构的脚本,然后才能使用/消费应用程序。

由于十二因素应用程序是自包含的,它需要某种机制来首先启动管理员管理流程然后才可用。幸运的是,随着 Docker 的兴起,此类任务变得更加容易。

这是最后一个因素。

但请稍等。安全呢?

云原生应用程序应了解身份验证和授权等安全方面。十二因素应用程序与支持服务集成;它可能不被允许,或者不应该被允许消费或使用这样的服务。

他们怎么会错过这样的规则?我们必须再增加一个因子,并有一个十三因子的应用程序。

Security

第十三个因素与安全有关——应用安全。云环境从数据中心跳转到数据中心,您的应用程序(可能是支持服务)需要保护其端点。您的应用程序可能会提供对有状态组件或业务相关功能的访问权限。你必须保护他们所有人。

如今,有许多框架可以帮助您完成此类任务,例如 SSO 系统、OAuth 和 OpenID Connect。

Microservices

微服务架构的主要概念已经在章节中描述2 微服务和反应式架构,微服务在其中部署、公开和使用。为微服务描述的大多数概念与云原生应用程序几乎相同。这就是为什么在大多数情况下,云原生应用程序是使用微服务方法实现的。

回顾最重要的概念,微服务应具有以下内容:

  • Single responsibility: It must be responsible for only one context—a business domain context; one and well done.
  • No sharing: It must be stateless and eventually delegate its persistency state to another backing service.
  • Black box: Its implementation must be hidden; the only shareable information is its API and the protocol used to expose its endpoints.
  • Private data: As per its hidden implementation, how data is stored is an implementation detail. Any data store can be used.

根据我们的旅程,我们将设计和实现一系列微服务,以实现一个名为 Cloud Football Manager 的整体应用程序。

该应用程序将由以下组件组成:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》云-本地应用程序

稍后,我们将从用户界面的角度、微服务的角度和数据存储的角度设计和实现每个组件。

如前所述,可以使用任何技术来设计和实现云原生应用程序。由于本书面向 Java 程序员,因此它将重点介绍 Spring Boot、Thorntail 和 Vert.x,它们是应用程序的运行时环境。

从微服务架构的角度来看,每个组件都可以针对不同的运行时环境来实现和运行;微服务之间的合作是由于通信协议。

Runtime environments

如前所述,云原生应用程序是一个独立的单元,因此它通常包含运行所需的一切。在撰写本文时,构建云原生应用程序或微服务最常用的框架如下:

  • Spring Boot
  • Thorntail (formerly WildFly Swarm)
  • Vert.x

Spring Boot

创建独立、生产级和易于运行的过程 Spring 由 Spring Boot 2 提供方便。 大多数 Spring Boot应用程序需要很少的 Spring 配置。

Spring Boot 提供以下功能:

  • Create standalone Spring applications
  • Embed Tomcat, Jetty, or Undertow directly (no need to deploy WAR files)
  • Dependency management through starters and various package manager integrations
  • Provide opinionated starter dependencies to simplify your build configuration
  • Automatically configure Spring and third-party libraries
  • Provide production-ready features
  • Absolutely no code generation and no requirement for XML configuration

随着 Spring Boot 的每个新版本,Java 生态系统的各种依赖项的版本都会升级。这在 Spring Boot 材料清单 (BOM) 中定义。

使用 Spring Boot 创建微服务非常简单;只需在您的 Maven 项目文件(即 pom.xml)中添加以下设置:

<properties>   
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>   
   <java.version>1.8</java.version>   
</properties>   
   
<dependencies>   
   <dependency>   
         <groupId>org.springframework.boot</groupId>   
         <artifactId>spring-boot-starter-jersey</artifactId>   
         <version>2.0.3.RELEASE</version>   
   </dependency>   
   
   <dependency>   
         <groupId>org.springframework.boot</groupId>   
         <artifactId>spring-boot-starter-test</artifactId>   
         <version>2.0.3.RELEASE</version>   
         <scope>test</scope>   
   </dependency>   
</dependencies>   
   
<build>   
   <plugins>   
         <plugin>   
         <groupId>org.springframework.boot</groupId>   
         <artifactId>spring-boot-maven-plugin</artifactId>   
         </plugin>   
   </plugins>   
</build>   

示例应用程序将类似于以下代码段:

package com.example.demo;   
   
import org.springframework.boot.SpringApplication;   
import   org.springframework.boot.autoconfigure.SpringBootApplication;   
   
@SpringBootApplication   
public class DemoApplication {   
   
    public static void main(String[]   args) {   
          SpringApplication.run(DemoApplication.class,   args);   
    }   
}   

此外,Spring 的网站提供了一个引导页面(http://start.spring.io/ a>),您可以在其中通过填写您需要的所有依赖项的表单来指定微服务的要求,如以下屏幕截图所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》云-本地应用程序

Thorntail

Thorntail span>将 Java EE 应用程序与所需的服务器运行时打包到 java-jar 您的应用程序中。这包括应用程序代码, 基本 WildFly 应用服务器,以及任何必要的依赖关系。 j ava-jar 可用于运行应用程序。它也与 MicroProfile 兼容。

它与最常用的框架完美集成,例如 Camel、Netflix OSS、Keycloak、Logstash 和 Swagger。由于其灵活且可插拔的 DNA,它允许您创建自己的 Java EE 运行时打包为可执行 JAR 文件(通常称为 Uber JAR 或 fat JAR),非常适合微服务方法。每个胖 JAR 本质上是一个微服务,然后可以独立升级、替换或扩展。 由于每个胖JAR都遵循单一职责原则,因此只会为其打包所需的依赖项。

Thorntail 通过提供对以下特性的支持,完全符合 Eclipse MicroProfile 规范:

  • MicroProfile
  • MicroProfile JWT RBAC Auth
  • MicroProfile Metrics
  • MicroProfile Rest Client
  • MicroProfile Config
  • MicroProfile Fault Tolerance
  • MicroProfile Health

使用 Thorntail 创建微服务非常简单;只需在您的 Maven 项目文件(即 pom.xml)中添加以下设置:

<properties>   
    <version.thorntail>2.0.0.Final</version.thorntail>   
  <maven.compiler.source>1.8</maven.compiler.source>   
    <maven.compiler.target>1.8</maven.compiler.target>   
    <failOnMissingWebXml>false</failOnMissingWebXml>   
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   
</properties>   
   
<dependencyManagement>   
  <dependencies>   
   <dependency>   
   <groupId>io.thorntail</groupId>   
   <artifactId>bom-all</artifactId>   
   <version>${version.thorntail}</version>   
   <scope>import</scope>   
   <type>pom</type>   
   </dependency>   
  </dependencies>   
</dependencyManagement>   
   
<dependency>   
   <groupid>io.thorntail</groupId>   
   <artifactId>jaxrs</artifactId>   
   <version>${version.thorntail}</version>   
</dependency>   
   
<plugin>   
    <groupid>io.thorntail</groupId>   
  <artifactId>thorntail-maven-plugin</artifactId>   
  <version>${version.thorntail}</version>   
  <executions>   
   <execution>   
   <goals>   
         <goal>package</goal>   
   </goals>   
   </execution>   
  </executions>   
</plugin>   

HelloWorldEndpoint 示例应用程序如下:

package com.example.demo.rest; 
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
@Path("/hello")
public class HelloWorldEndpoint { @GET @Produces("text/plain") public Response doGet() { return Response.ok("Hello from Thorntail!").build(); } }

RestApplication 的代码片段如下:

package com.example.demo.rest; 
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
publicclass RestApplication extends Application {
}

此外,Thorntail 的网站提供了一个引导页面(https://thorntail.io/generator/ ),您可以通过在表单中​​填写您需要的所有依赖项来指定微服务的需求,如以下屏幕截图所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》云-本地应用程序

Vert.x

Vert.x 是 Eclipse 基金会的一个开源框架,用于构建反应式和多语言软件。它是响应式的,因为它使用异步流来响应任何更改或事件。

它是多语言的,因为它支持同样基于 JVM 的不同编程语言,例如 Java、Groovy、Ruby、Python 和 JavaScript。

Vert.x 与其竞争对手 Node.js 一样,使用事件总线(技术上是循环)与应用程序的组件交互,将事件传递给适当的处理程序以异步管理它们。

Vert.x 带有一些需要解释的概念。

Verticles

Verticle 是由 Vert.x 引擎执行的一小段代码(至少应该很小)。该框架带有许多不同的抽象顶点,可以根据任何需要使用和扩展。在 Java 中,可以使用 io.vertx.core.Verticle 接口或其任何一个子类来实现 Verticle。

Event bus

事件总线是 Vert.x 应用程序系统的核心。每个 Verticle 使用事件总线与其他 Verticle 通信。这意味着,一旦消息或事件循环到事件总线中,该消息就会被传递到适当的 Verticle。然后,verticle 通过读取事件(它可以包含对象或任何原始数据类型,如字符串或数字)并采取适当的操作来做出反应。
事件和消息是异步处理的,因此每次 Verticle 产生消息时,后者以队列的形式发送到总线,控制权返回给verticle。稍后,当计算资源可用时,侦听的 Verticle 获取事件并使用 Futurecallback 方法发回响应。

使用 Vert.x 创建微服务非常简单;只需在您的 Maven 项目文件(即 pom.xml)中添加以下设置:

<properties>   
   <java.version>1.8</java.version>   
   <vertx.version>3.5.3</vertx.version>   
</properties>   
   
<build>   
   <plugins>   
         <plugin>   
         <groupId>org.apache.maven.plugins</groupId>   
         <artifactId>maven-compiler-plugin</artifactId>   
         <version>3.5.1</version>   
         <configuration>   
               <source>${java.version}</source>   
               <target>${java.version}</target>   
         </configuration>   
         </plugin>   
         <plugin>   
         <groupId>org.apache.maven.plugins</groupId>   
         <artifactId>maven-shade-plugin</artifactId>   
         <version>2.4.3</version>   
         <executions/>   
         </plugin>   
         <plugin>   
         <groupId>org.codehaus.mojo</groupId>   
         <artifactId>exec-maven-plugin</artifactId>   
         <version>1.5.0</version>   
         <configuration>   
               <mainClass>io.vertx.core.Launcher</mainClass>   
               <arguments>   
                     <argument>run</argument>   
                     <argument>com.example.demo.MainVerticle</argument>   
               </arguments>   
         </configuration>   
         </plugin>   
   </plugins>   
</build>   
   
<dependencies>   
         <dependency>   
         <groupId>io.vertx</groupId>   
         <artifactId>vertx-unit</artifactId>   
         <version>${vertx.version}</version>   
         </dependency>   
         <dependency>   
         <groupId>io.vertx</groupId>   
         <artifactId>vertx-core</artifactId>   
         <version>${vertx.version}</version>   
         </dependency>   
         <dependency>   
         <groupId>io.vertx</groupId>   
         <artifactId>vertx-web</artifactId>   
         <version>${vertx.version}</version>   
         </dependency>   
</dependencies>   

示例应用程序如下所示:

package com.packt.vertx;   
   
import io.vertx.core.AbstractVerticle;   
   
public class MainVerticle extends   AbstractVerticle {   
   
   @Override   
   public void start() throws Exception {   
         vertx.createHttpServer().requestHandler(req   -> {   
               req.response()   
               .putHeader("content-type", "text/plain")   
               .end("Running Vert.x!");   
         }).listen(8080);   
         System.out.println("HTTP server started on port 8080");   
   }   
}   

此外,Vert.x 的网站提供了一个引导页面 (http://start.vertx.io/),其中您可以通过在表单中​​填写您需要的所有依赖项来指定微服务的需求,如以下屏幕截图所示:

读书笔记《hands-on-cloud-native-microservices-with-jakarta-ee》云-本地应用程序

Summary

在本章中,我们了解了云原生应用程序是什么以及它应该具备的所有特性来支持自然分布的云架构。

我们还研究了应该构成云原生应用程序的十二个因素,增加了一个因素,即安全性。随着技术的快速发展,twelve-factor 应用程序概念也应该通过删除和添加新因素来更新。我们还描述了微服务的实施原则。

最后,我们给出了使用 Spring Boot、Thorntail 和 Vert.x 等不同框架在不同运行时环境中的 云原生应用程序 的示例。

在下一章中,我们将开始更详细地介绍如何使用微服务构建云原生应用程序,从头开始构建足球经理应用程序。