读书笔记《第一部分 使用 Spring Boot 开始微服务开发》第1章微服务简介
PART I
Getting Started with Microservice Development Using Spring Boot
在这一部分中,您将学习如何使用 Spring Boot 的一些最重要的特性来开发微服务。
本部分包括以下章节:
- 第 1 章,微服务简介
- 第二章,Spring Boot简介
- 第 3 章,创建一组协作微服务
- 第 4 章,使用 Docker 部署我们的微服务
- 第 5 章,使用 OpenAPI 添加 API 描述
- 第 6 章,添加持久性
- 第 7 章,开发响应式微服务
Introduction to Microservices
本书并没有一味地赞美微服务。相反,它是关于我们如何利用它们的优势,同时能够应对构建可扩展、有弹性和可管理的微服务的挑战。
作为本书的介绍,本章将涵盖以下主题:
- 我如何了解微服务以及我对它们的好处和挑战有哪些经验
- 什么是基于微服务的架构?
- 微服务的挑战
- 处理挑战的设计模式
- 可以帮助我们应对这些挑战的软件推动者
- 本书未涵盖的其他重要注意事项
技术要求
本章不需要安装。但是,您可能有兴趣查看 C4 模型约定,https://c4model.com ,因为本章中的插图受到 C4 模型的启发。
本章不包含任何源代码。
我的微服务之路
当我在 2014 年第一次了解 微服务的概念时,我意识到我已经开发微服务(嗯,有点)很多年了,但我并不知道它是微服务。正在处理。我参与了一个始于 2009 年的项目,我们开发了一个基于一组独立功能的平台。该平台已交付给在本地部署它的许多客户。为了方便客户从平台中挑选他们想要使用的功能,每个功能都 开发为自主软件组件< /强>;也就是说,它有自己的持久数据,并且只使用定义良好的 API 与其他组件进行通信。
由于无法讨论该项目平台的具体功能,所以我将组件的名称概括为从 Component A 到 Component F。平台组成为一组组件如下图所示:

图 1.1:平台的组成
从图中我们还可以看出,每个组件都有自己的持久数据存储,并且不与其他组件共享数据库。
使用 Java 和 Spring 框架开发每个组件,打包为 WAR 文件并部署为 Java EE Web 容器(例如 Apache Tomcat)中的 Web 应用程序。根据客户的具体要求,该平台可以部署在单台或多台服务器上。两节点部署可能如下所示:

图 1.2:两节点部署场景
自治软件组件的好处
从这个项目中,我了解到将平台的功能分解为一组自主软件组件提供了 一些好处:
- A customer can deploy parts of the platform in its own system landscape, integrating it with its existing systems using its well-defined APIs.
下面是一个示例,其中一位客户决定部署 Component A、Component B、Component D,以及来自平台的组件E,并将它们与客户系统环境中的两个现有系统系统A集成> 和 系统 B:
图 1.3:平台的部分部署
- 另一个客户可以选择用客户系统环境中已经存在的实现来替换平台的部分功能,可能 需要采用平台 API 中的现有功能。以下是客户将平台中的 Component C 和 Component F 替换为自己的实现的示例: <图类=“媒体对象”>
图 1.4:更换平台部件
- Each component in the platform can be delivered and upgraded separately. Thanks to the use of well-defined APIs, one component can be upgraded to a new version without being dependent on the life cycle of the other components.
以下是 Component A 从版本 v1.1 升级到 v1 的示例.2。 Component B,调用Component A,使用了定义好的API,不需要升级;也就是说,升级后还是一样的(或者至少是向后兼容的):
图 1.5:升级特定组件
- 由于 使用定义明确的 API,平台中的每个组件也可以独立于其他组件横向扩展到多个服务器。可以进行扩展以满足高可用性要求或处理更多请求。在这个特定项目中,它是通过手动在多个服务器前设置负载平衡器来实现的,每个服务器都运行一个 Java EE Web 容器。 Component A 已扩展到三个实例的示例如下所示: <图类=“媒体对象”>
图 1.6:扩展平台
自主软件组件的挑战
我的团队还了解到,分解平台带来了许多新挑战, 我们在开发更传统的单体应用程序时没有遇到(至少没有相同程度):
- 向组件添加新实例需要手动配置负载均衡器并手动设置新节点。这项工作既费时又容易出错。
- 该平台最初容易出现由与其通信的其他系统引起的错误。如果系统停止及时响应平台发送的请求,平台很快就会耗尽关键资源,例如操作系统线程,特别是在暴露于大量并发请求时。这导致平台中的组件挂起甚至崩溃。由于平台中的大部分通信都是基于同步通信,一个组件崩溃会导致级联故障;也就是说,崩溃组件的客户端也可能在一段时间后崩溃。这是 称为失败链。
- 使所有组件实例中的配置保持一致和最新很快成为一个问题,导致大量手动和重复性工作。这不时导致质量问题。
- 在延迟问题和硬件使用(例如 CPU、内存、磁盘和网络的使用)方面监控平台的 状态比监控单个单体应用程序的实例。
- 从多个分布式组件收集日志文件并关联来自组件的相关日志事件也很困难,但由于组件的数量是固定的并且事先已知,因此是可行的。
随着时间的推移,我们解决了前面列表中提到的大多数挑战,并结合了内部开发的工具和有据可查的手动处理这些挑战的说明。总体而言,该操作的规模处于可以接受发布新版本组件和处理运行时问题的手动过程的水平,即使它们并不理想。
进入微服务
2014 年学习基于微服务的架构让我意识到其他项目也 在努力应对类似的挑战(部分原因与我之前描述的不同,例如,大型满足网络规模要求的云服务提供商)。许多微服务先驱发布了他们学到的经验教训的详细信息。从这些课程中学习非常有趣。
许多先驱者最初开发的单体应用程序使他们从业务角度非常成功。但随着时间的推移,这些单体应用程序变得越来越难以维护和发展。他们也变得难以扩展超出 可用最大机器的功能(也称为垂直扩展)。最终,先驱们开始想方设法将单体应用程序拆分成更小的组件,这些组件可以相互独立地发布和扩展。缩放 小组件可以使用水平缩放来完成,即将一个组件部署在多个较小的服务器上并放置一个负载平衡器在它前面。如果在云中完成,扩展能力可能是无穷无尽的——这只是你引入多少虚拟服务器的问题(假设你的组件可以在大量实例上扩展,但稍后会更多)。
2014 年,我还了解了一些新的开源项目,这些项目提供了简化微服务开发的工具和框架,可用于应对微服务带来的挑战 基于架构。其中一些如下:
- Pivotal 发布了Spring Cloud,它按顺序封装了Netflix OSS的部分内容 提供动态服务发现、配置管理、分布式跟踪、断路等能力。
- I also learned about Docker and the container revolution, which is great for minimizing the gap between development and production. Being able to package a component not only as a deployable runtime artifact (for example, a Java
war
orjar
file) but as a complete image, ready to be launched as a container on a server running Docker, was a great step forward for development and testing.现在,将容器视为一个孤立的进程。我们将在第 4 章,使用 Docker 部署我们的微服务中了解有关容器的更多信息。
- Docker 等容器引擎不足以在生产环境中使用容器。需要一些东西来确保所有容器都启动并运行,并且可以在许多服务器上横向扩展容器,从而提供高可用性和增加的计算资源。
- These types of product became known as container orchestrators. A number of products have evolved over the last few years, such as Apache Mesos, Docker in Swarm mode, Amazon ECS, HashiCorp Nomad, and Kubernetes. Kubernetes was initially developed by Google. When Google released v1.0 in 2015, they also donated Kubernetes to CNCF (https://www.cncf.io/). During 2018, Kubernetes became kind of a de facto standard, available both pre-packaged for on-premises use and as a service from most of the major cloud providers.
正如 https://kubernetes .io/blog/2015/04/borg-predecessor-to-kubernetes/,Kubernetes实际上是一个基于开源的内部容器编排器的重写,命名为 Borg,在 Kubernetes 项目成立之前被 Google 使用了十多年。
示例微服务环境
由于本书无法涵盖我刚才提到的技术的所有方面. 我将描述如何一起使用它们来创建可管理、可扩展和有弹性的协作微服务。
本书的每一章都将解决一个特定的问题。为了演示事物是如何组合在一起的,我将使用一小组协作的微服务,我们将在本书中不断发展这些微服务。 第 3 章,创建一组协作微服务中将描述微服务的格局;现在,知道它看起来像这样就足够了:

图 1.7:书中使用的基于微服务的系统架构
请注意,这是一个非常小的协作微服务系统环境。对于这几个微服务,我们将在接下来的章节中添加的周边支持服务可能看起来非常复杂。但请记住,本书中介绍的解决方案旨在支持更大的系统环境。
现在我们已经了解了微服务的潜在好处和挑战,让我们开始研究如何定义微服务。
定义微服务
微服务架构是 关于将单体应用程序拆分为更小的组件,它实现了两个主要目标:
- 更快的开发,实现持续部署
- 更易于手动或自动扩展
微服务本质上是一个自治的软件组件,可以独立升级、替换和扩展。为了能够充当自治组件,它必须满足某些标准,如下所示:
- 它必须符合无共享架构;也就是说,微服务之间不共享数据库中的数据!
- 它只能通过定义良好的接口进行通信,或者使用 API 和同步服务,或者最好通过异步发送消息。使用的 API 和消息格式必须是稳定的、有据可查的,并且通过遵循定义的版本控制策略不断发展。
- 它必须部署为单独的运行时进程。微服务的每个实例都在单独的运行时进程中运行,例如 Docker 容器。
- 微服务实例是无状态的,因此对微服务的传入请求可以由其任何实例处理。
使用一组协作的微服务,我们可以部署到多个较小的服务器上,而不是像部署单体应用程序时那样被迫部署到单个大型服务器上。
鉴于已满足上述标准,与扩展大型单体应用程序相比,将单个微服务扩展为更多实例(例如,使用更多虚拟服务器)更容易。
利用云中可用的自动缩放功能也是一种可能性,但对于大型单体应用程序通常不可行。与升级大型单体应用程序相比,升级甚至替换单个微服务也更容易。
下图说明了这一点,其中一个单体应用程序已被划分为六个微服务,所有这些微服务都已部署到单独的服务器中。一些微服务也独立于其他微服务进行了扩展:

图 1.8:将单体架构划分为微服务
我从客户那里收到的一个非常常见的问题是:
How big should a microservice be?
我尝试使用以下经验法则:
- 小到可以装进开发者的脑袋
- 足够大,不会危及性能(即延迟)和/或数据一致性(存储在不同微服务中的数据之间的 SQL 外键不再是理所当然的事情)
因此,总而言之, 微服务架构本质上是一种架构风格,我们将单体应用程序分解为一组协作的自治软件组件。其动机是实现更快的开发并使其更容易扩展应用程序。
通过更好地理解如何定义微服务,我们可以继续并详细说明微服务系统环境带来的挑战。
微服务的挑战
在自主软件组件的挑战部分,我们已经看到了 自主软件组件可能带来的一些挑战(以及它们都适用于微服务)如下:
- 许多使用同步通信的小组件可能会导致连锁故障问题,尤其是在高负载下
- 使许多小型组件的配置保持最新可能具有挑战性
- 很难跟踪正在处理且涉及许多组件的请求,例如,在执行根本原因分析时,每个组件都在本地存储日志记录
- 在组件级别分析硬件资源的使用也可能具有挑战性
- 许多小组件的手动配置和管理可能会变得昂贵且容易出错
将应用程序分解为一组自治组件的另一个 缺点(但最初并不总是很明显)是它们形成了一个分布式系统 .众所周知,分布式系统 就其本质而言,很难处理。这已为人所知多年(但在许多情况下被忽视,直到证明不同)。我最喜欢证实这一事实的引述来自 Peter Deutsch,他早在 1994 年就说过以下话:
分布式计算的 8 个谬误:基本上每个人在第一次构建分布式应用程序时都会做出以下八个假设。从长远来看,所有这些都被证明是错误的,都会造成很大的麻烦和痛苦的学习经历:
1.网络可靠
2.延迟为零
3.带宽是无限的
4.网络安全
5. 拓扑不变
6. 有一名管理员
7.运输成本为零
8.网络是同质的
——彼得·多伊奇,1994
一般来说,基于这些错误假设构建微服务会导致解决方案容易出现临时网络故障和其他微服务实例中出现的问题。当系统环境中的微服务数量增加时,出现问题的可能性也会增加。一个好的经验法则是根据 系统环境中总是出现问题的假设来设计您的微服务架构。微服务架构需要被设计来处理这个问题,在检测问题和重启失败的组件方面。此外,在客户端,确保请求不会发送到失败的微服务实例。当问题得到纠正时,应恢复对先前失败的微服务的请求;也就是说,微服务客户端需要具有弹性。当然,所有这些都需要完全自动化。微服务数量众多,运维人员手动处理是行不通的!
这个范围很大,但我们现在将限制自己并继续学习微服务的设计模式。
微服务的设计模式
本主题将介绍使用 设计模式来缓解微服务带来的挑战,如前一节所述。在本书的后面,我们将看到如何使用 Spring Boot、Spring Cloud、Kubernetes 和 Istio 来实现这些设计模式。
设计模式的概念其实很古老;它是由 Christopher Alexander 在 1977 年发明的。本质上,设计模式是关于在给定特定上下文时描述问题的可重用解决方案。与花时间自己发明解决方案相比,使用来自设计模式的久经考验的解决方案可以节省大量时间并提高实施质量。
我们将介绍的设计模式如下:
- 服务发现
- 边缘服务器
- 反应式微服务
- 中央配置
- 集中式日志分析
- 分布式跟踪
- 断路器
- 控制回路
- 集中监控和报警
此列表并不全面;相反,它是处理我们之前描述的挑战所需的设计模式的最小列表。
我们将使用轻量级的 方法来描述设计模式,并重点关注以下内容:
- 问题
- 一个解法
- 解决方案要求
在本书中,我们将更深入地研究如何应用这些设计模式。这些设计模式的上下文是协作微服务的系统环境,其中微服务使用同步请求(例如,使用 HTTP)或通过发送异步消息(例如,使用消息代理)相互通信。
服务发现
问题
微服务实例通常在启动时分配动态分配的 IP 地址,例如在容器中运行时。这使得客户端很难向微服务发出请求,例如,通过 HTTP 公开 REST API。考虑下图:

图 1.9:服务发现问题
解决方案
在系统环境中添加一个新组件——服务发现服务,它跟踪当前可用的 微服务和IP地址它的实例。
解决方案要求
- 自动注册/注销微服务及其实例。
- 客户端必须能够向微服务的逻辑端点发出请求。该请求将被路由到可用的微服务实例之一。
- 对微服务的请求必须在可用实例上进行负载平衡。
- 我们必须能够检测当前不健康的实例,以便不会将请求路由到它们。
实现说明:正如我们将看到的,在第 9 章中,使用 Netflix Eureka 添加服务发现,第 15 章,Kubernetes 简介,和 第 16 章,将我们的微服务部署到 Kubernetes,这个 设计模式可以使用两种不同的策略来实现:
- 客户端路由: 客户端使用与服务发现服务通信的库来找出合适的实例来发送请求。
- 服务器端路由: 服务发现服务的基础设施还公开了一个反向代理,所有请求都发送到该代理。反向代理代表客户端将请求转发到适当的微服务实例。
边缘服务器
问题
在微服务的系统环境中, 在许多情况下都希望将一些微服务暴露在系统环境之外,并隐藏剩余的微服务以防止外部访问。必须保护暴露的微服务免受来自恶意客户端的请求。
解决方案
添加一个 新组件,一个边缘服务器,到所有传入请求都会经过的系统环境:

图 1.10:边缘服务器设计模式
实施说明:边缘服务器 的行为通常类似于反向代理,可以与发现服务集成以提供动态负载平衡能力。
解决方案要求
- 隐藏不应暴露在其上下文之外的内部服务;也就是说,仅将请求路由到配置为允许外部请求的微服务
- 暴露外部服务并保护它们免受恶意请求;即使用标准协议和最佳实践(例如 OAuth、OIDC、JWT 令牌和 API 密钥)来确保客户端是可信赖的
反应式微服务
问题
传统上,作为 Java 开发人员,我们习惯于使用 阻塞 I/O 来实现同步通信,例如,基于 HTTP 的 RESTful JSON API。使用阻塞 I/O 意味着从操作系统为请求的长度分配一个线程。如果并发请求的数量增加,服务器可能会用尽操作系统中的可用线程,从而导致响应时间延长到服务器崩溃等问题。使用微服务架构通常会使这个问题变得更糟,其中通常使用协作微服务链来服务请求。服务请求所涉及的微服务越多,可用线程耗尽的速度就越快。
解决方案
使用非阻塞 I/O 确保在另一个服务(即数据库或另一个微服务)中等待处理发生时没有分配线程。
解决方案要求
- 只要可行,就使用异步编程模型,发送消息而不等待接收者处理它们。
- 如果首选同步编程模型,请使用可以使用非阻塞 I/O 执行同步请求的反应式框架,而无需在等待响应时分配线程。这将使微服务更容易扩展,以处理增加的工作量。
- 微服务还必须设计为具有弹性和自我修复能力。弹性意味着即使它所依赖的服务之一失败,也能够产生响应;自我修复意味着一旦失败的服务再次运行,微服务必须能够恢复使用它。
2013 年,设计反应式系统的关键原则 在反应式宣言(https://www.reactivemanifesto.org/)。
根据宣言,反应式系统的基础是它们是消息驱动的;他们使用异步通信。这使它们具有弹性(即可扩展)和弹性(即可以容忍故障)。弹性和弹性共同使反应系统能够始终及时响应。
中央配置
问题
传统上,应用程序与其配置一起部署,例如,一组环境变量和/或文件 包含配置信息。给定基于微服务架构的系统环境,即部署了大量微服务实例,会出现一些查询:
- 如何全面了解所有正在运行的微服务实例的配置?
- 如何更新配置并确保所有受影响的微服务实例都正确更新?
解决方案
添加一个新的 组件,即一个配置服务器,以存储所有微服务的配置,如图所示下图:

图 1.11:中央配置设计模式
解决方案要求
可以 将一组微服务的配置信息存储在一个地方,针对不同的环境使用不同的设置(例如,dev、test、qa 和 prod)。
集中式日志分析
问题
传统上, 应用程序将日志事件写入日志文件,这些日志文件存储在运行应用程序的服务器的本地文件系统中。给定基于微服务架构的系统架构,即在大量较小的服务器上部署大量微服务实例,我们可以提出以下问题:
- 当每个微服务实例写入自己的本地日志文件时,我如何了解系统环境中正在发生的事情?
- 如何确定是否有任何微服务实例出现问题并开始将错误消息写入其日志文件?
- 如果最终用户开始报告问题,我如何找到相关的日志消息;也就是说,如何识别 哪个微服务实例是问题的根本原因?下图说明了这个问题: <图类=“媒体对象”>
图 1.12:微服务将日志文件写入其本地文件系统
解决方案
- 检测新的微服务实例并从中收集日志事件
- 在中央数据库中以结构化和可搜索的方式解释和存储日志事件
- 提供用于查询和分析日志事件的 API 和图形工具
解决方案要求
- 微服务将日志事件流式传输到标准系统输出,
stdout
。与将日志事件写入特定于微服务的日志文件相比,这使日志收集器更容易找到日志事件。 - 微服务使用下一节中描述的关于 分布式跟踪 设计模式的相关 ID 标记日志事件。
- 定义了规范的日志 格式,以便日志收集器可以在将日志事件存储到中央数据库之前将从微服务收集的日志事件转换为规范的日志格式。需要以规范的日志格式存储日志事件,以便能够查询和分析收集的日志事件。
分布式跟踪
问题
在处理对系统环境的外部请求时,必须能够跟踪在微服务之间流动的 请求和消息。
一些故障场景示例如下:
- 如果最终用户开始针对特定故障提交支持案例,我们如何确定导致问题的微服务,即根本原因?
- 如果一个支持案例提到与特定实体相关的问题,例如,特定订单号,我们如何找到与处理此特定订单相关的日志消息——例如,来自参与处理它的所有微服务的日志消息?
- 如果最终用户开始提交有关响应时间过长的支持案例,我们如何确定调用链中的哪个微服务导致延迟?
下图描述了这一点:

图 1.13:分布式跟踪问题
解决方案
为了跟踪协作微服务之间的处理 ,我们需要确保所有相关的请求和消息都标记有一个共同的相关ID和 相关 ID 是所有日志事件的一部分。基于关联ID,我们可以使用集中式日志服务来查找所有相关的日志事件。如果其中一个日志事件还包含有关业务相关标识符的信息,例如客户、产品或订单的 ID,我们可以使用相关 ID 找到该业务标识符的所有相关日志事件。
为了能够分析协作微服务调用链中的延迟,我们必须能够收集请求、响应和消息进入和退出每个微服务的时间戳。
解决方案要求
- 将唯一的相关 ID 分配给已知位置的所有传入或新请求和事件,例如具有标准化名称的标头
- 微服务发出请求或发送消息时,必须在请求和消息中添加相关 ID
- 所有日志事件都必须包含预定义格式的相关 ID,以便集中式日志记录服务可以从日志事件中提取相关 ID 并使其可搜索
- 必须为请求、响应和消息进入或退出微服务实例时创建跟踪记录
断路器
问题
使用同步相互通信的微服务的系统环境可能会暴露于故障链。如果一个微服务停止响应,它的客户端也可能会遇到问题并停止响应客户端的请求。该问题可以在整个系统环境中递归传播并消除其中的主要部分。
这在使用阻塞 I/O 执行同步请求的情况下尤其常见,即在处理请求时阻塞来自底层操作系统的线程。再加上大量并发请求和开始响应缓慢的服务,线程池可能会很快耗尽,导致调用者挂起和/或崩溃。这种失败会迅速传播给调用者的调用者,以此类推。
解决方案
添加一个断路器,如果它检测到调用的服务有问题, 会阻止调用者发出新的传出请求。
解决方案要求
- 如果检测到服务问题,打开电路并快速失败(无需等待超时)。
- 故障探测 校正(也称为半开电路);即定期允许单个请求通过,以查看服务是否再次正常运行。
- 如果探针检测到服务再次正常运行,关闭电路。这种能力非常重要,因为它使系统环境能够适应这些类型的问题;换句话说,它可以自我修复。
下图说明了一个场景,其中微服务系统环境中的所有同步通信都通过断路器。所有断路器闭合;它们允许流量,除了一个断路器(对于 Microservice E)检测到请求所访问的服务存在问题。因此,该断路器是断开的,并利用了快速故障逻辑;也就是说,它不会调用失败的服务并等待发生超时。相反,微服务 E 可以立即返回响应,可选择在响应之前应用一些后备逻辑:

图 1.14:断路器设计模式
控制回路
问题
在一个系统 环境中,大量的微服务实例分布在多个服务器上,手动检测和纠正诸如崩溃或挂起的微服务实例等问题是非常困难的。
解决方案
在系统环境中添加一个新的 组件,即一个控制循环。这个过程如下图所示:

图 1.15:控制回路设计模式
解决方案要求
控制循环 将不断观察系统格局的实际状态,并将其与进行比较所需状态,由操作员指定。如果两个状态不同,它将采取行动使实际状态等于期望状态。
实现说明:在容器的世界中,容器编排器(例如 Kubernetes)通常用于实现这种模式。我们将在第 15 章,Kubernetes 简介中了解更多关于 Kubernetes 的信息。
集中监控和报警
对于这种模式,我们 具有 以下问题、解决方案和解决方案要求。
问题
如果观察到 响应时间和/或硬件资源的使用率高得无法接受,则很难发现问题的根本原因。例如,我们需要能够分析每个微服务的硬件资源消耗。
解决方案
为了抑制这种情况,我们 向 添加了一个新组件监控服务 a> 系统景观,能够收集有关每个微服务实例级别的硬件资源使用情况的指标。
解决方案要求
- 它必须能够从系统环境使用的所有服务器收集指标,其中包括自动缩放服务器
- 它必须能够检测新的微服务实例,因为它们在可用服务器上启动并开始从它们收集指标
- 它必须能够提供 API 和图形工具来查询和分析收集的指标
- 必须可以定义在指定指标超过指定阈值时触发的警报
以下屏幕截图显示了 Grafana,它将 Prometheus 的指标可视化,这是一个监控工具,我们将在 第 20 章,监控微服务中看到:

图 1.16:使用 Grafana 进行监控
那是一个 广泛的列表!我相信这些设计模式可以帮助您更好地理解微服务面临的挑战。接下来,我们将继续学习软件使能器。
软件推动者
正如我们已经提到的,我们 拥有许多非常好的开源工具,可以帮助我们满足我们对微服务的期望,最重要的是,可以应对即将到来的新挑战跟他们:
- Spring Boot,一个应用 框架
- Spring Cloud/Netflix OSS, 应用程序框架和即用型< /a>服务
- Docker,用于 在单个服务器中运行容器的工具
- Kubernetes,一个容器 协调器,用于管理运行容器的服务器集群
- Istio,一个服务 mesh 实现
下表列出了我们应对这些挑战所需的 设计模式,以及本书中用于实现设计模式的相应开源工具:
Design Pattern |
Spring Boot |
Spring Cloud |
Kubernetes |
Istio |
Service discovery |
Netflix Eureka and Spring Cloud LoadBalancer |
Kubernetes |
||
Edge server |
Spring Cloud and Spring Security OAuth |
Kubernetes Ingress controller |
Istio ingress gateway |
|
Reactive microservices |
Project Reactor and Spring WebFlux |
|||
Central configuration |
Spring Config Server |
Kubernetes |
||
Centralized log analysis |
Elasticsearch, Fluentd, and Kibana Note: Actually not part of Kubernetes, but can easily be deployed and configured together with Kubernetes |
|||
Distributed tracing |
Spring Cloud Sleuth and Zipkin |
Jaeger |
||
Circuit breaker |
Resilience4j |
Outlier detection |
||
Control loop |
Kubernetes controller managers |
|||
Centralized monitoring and alarms |
Kiali, Grafana, and Prometheus |
请注意,Spring Cloud、Kubernetes 或 Istio 中的任何一个都可以用于实现一些设计模式,例如 服务发现、边缘服务器和中央配置。我们将在本书后面讨论使用这些替代方案的利弊。
随着本书介绍的设计模式和工具的介绍,我们将通过一些相关领域来结束本章,这些领域也很重要,但本文未涉及。
其他重要注意事项
为了在实现微服务架构方面取得成功,还需要考虑许多相关领域。我不会在本书中涉及这些领域。相反,我将在这里简要提及它们,如下所示:
- DevOps 的重要性:微服务架构的 好处之一是它可以缩短交付时间,并且在极端情况下,允许持续交付新版本。为了能够快速交付,您需要建立一个组织,让开发人员和运维人员在你构建它,你运行它的口头禅下一起工作。这意味着不再允许开发人员简单地将软件的新版本传递给运营团队。相反,开发和运维组织需要更紧密地合作,组织成对一个微服务(或一组相关微服务)的端到端生命周期负全部责任的团队。除了开发/运营的组织部分,团队还需要自动化交付链,即构建、测试、打包和部署微服务到各种部署环境的步骤。这是 称为设置交付管道。
- Organizational aspects and Conway's law: Another interesting aspect of how a microservice architecture might affect the organization is Conway's law, which states the following:
“任何设计系统(定义广泛)的组织都将产生其结构是组织通信结构副本的设计。”
——梅尔文·康威,1967
这意味着基于技术专长(例如,UX、业务逻辑和数据库团队)为大型应用程序组织 IT 团队的传统方法将导致大型三层应用程序——通常是一个大型单体应用程序,其中包含一个单独的UI的可部署单元,一个用于处理业务逻辑,一个用于大数据库。要成功交付基于微服务架构的应用程序,需要将组织 更改为使用一个或一组相关微服务的团队。团队必须具备这些微服务所需的技能,例如,用于业务逻辑的语言和框架以及用于持久化其数据的数据库技术。
- Decomposing a monolithic application into microservices: One of the most difficult decisions (and expensive if done wrong) is how to decompose a monolithic application into a set of cooperating microservices. If this is done in the wrong way, you will end up with problems such as the following:
- Slow delivery: Changes in the business requirements will affect too many of the microservices, resulting in extra work.
- Bad performance: To be able to perform a specific business function, a lot of requests have to be passed between various microservices, resulting in long response times.
- Inconsistent data: Since related data is separated into different microservices, inconsistencies can appear over time in data that's managed by different microservices.
为微服务找到合适的 边界的一个好方法是应用域驱动设计及其 有界上下文的概念。根据 Eric Evans 的说法,有界上下文是:
"A description of a boundary (typically a subsystem, or the work of a particular team) within which a particular model is defined and applicable."
这意味着由有界上下文定义的微服务将具有其自身数据的定义良好的模型。
- API 设计的重要性:如果一组 微服务公开了一个通用的、外部可用的 API,那么 API 是否简单很重要了解并遵守以下准则:
- 如果在多个API中使用相同的概念,在命名和使用的数据类型方面应该有相同的描述。
- 允许 API 以独立但受控的方式发展是非常重要的 。这通常需要 为 API 应用适当的版本控制架构,例如 https://semver.org/。这意味着在特定时间段内支持 API 的多个主要版本,允许 API 的客户按照自己的节奏迁移到新的主要版本。
- 从本地到云端的迁移路径:如今,许多公司在本地运行他们的工作负载,但 正在寻找方法将部分工作负载迁移到云端。由于当今大多数云提供商都提供 Kubernetes 即服务,因此一种有吸引力的迁移方法可以是首先将工作负载移动到本地 Kubernetes(作为微服务或不作为微服务),然后将其重新部署到由首选云提供商提供的 Kubernetes 即服务产品。
- 良好的微服务设计原则,12 要素应用程序:12 要素应用程序(< span class="url">https://12factor.net) 是一套 设计原则,用于构建可以部署在云。这些设计原则中的大多数 适用于构建微服务,而不管它们将在何处以及如何部署,即在云中或本地。本书将介绍其中一些原则,例如配置、进程和日志,但不是全部。
第一章就是这样!我希望这能让你对微服务和随之而来的挑战有一个很好的基本概念,以及我们将在本书中介绍的内容的概述。
概括
在这个介绍性章节中,我描述了自己进入微服务的方式,并深入研究了它们的一些历史。我们定义了微服务是什么——一种具有一些特定要求的自治分布式组件。我们还了解了基于微服务架构的优点和挑战性方面。
为了应对这些挑战,我们定义了一组设计模式,并将 Spring Boot、Spring Cloud、Kubernetes 和 Istio 等开源产品的功能简要映射到设计模式。
您现在渴望开发您的第一个微服务,对吧?在下一章中,我们将介绍 Spring Boot 和互补的开源工具,我们将使用它们来开发我们的第一个微服务。