阿里高级技术师:使用 Spring Cloud 和 Docker 的微服务架构

如何使用 Spring Boot、Spring Cloud、Docker 和 Netflix 的一些开源工具设置微服务架构。

本文通过一个使用 Spring Boot、Spring Cloud 和 Docker 构建的概念验证应用程序的示例,为理解常见的微服务架构模式提供了一个起点。

代码在 Github上可用,图像在 Docker Hub 上可用。您只需一个命令即可启动整个系统。

作为这个系统的基础,我选择了一个旧项目,它的后端曾经是一个单体应用程序。该应用程序提供了一种处理个人财务、组织收入和支出、管理储蓄、分析统计数据和创建简单预测的方法。

功能服务

单体应用程序被分解为三个核心微服务。所有这些都是可独立部署的应用程序,围绕某些业务功能进行组织。

账户服务

包含一般用户输入逻辑和验证:收入/支出项目、储蓄和帐户设置

统计局

对主要统计参数执行计算并捕获每个帐户的时间序列。数据点包含标准化为基础货币和时间段的值。此数据可用于跟踪帐户生命周期中的现金流动态。

通知服务

存储用户的联系信息和通知设置(如提醒和备份频率)。计划工作人员从其他服务收集所需信息,并向订阅的客户发送电子邮件消息。

笔记

  • 每个微服务都有自己的数据库,因此无法绕过 API 直接访问持久性数据。
  • 对于这个项目,我使用 MongoDB 作为每个服务的主数据库。拥有多语言持久性架构也可能有意义(选择最适合服务需求的数据库类型)。
  • 服务到服务的通信非常简单:微服务只使用同步 REST API 进行通信。现实世界系统中的常见做法是使用交互风格的组合。例如,执行同步 GET 请求以检索数据,并通过消息代理使用异步方法进行创建/更新操作,以解耦服务和缓冲消息。然而,这给我们带来了最终的一致性世界。

基础设施服务

分布式系统中有很多通用模式,它们可以帮助我们使描述的核心服务工作。Spring Cloud 提供了强大的工具来增强 Spring Boot 应用程序的行为以实现这些模式。我将简要介绍它们。

配置服务

Spring Cloud Config 是分布式系统的水平可扩展集中配置服务。它使用当前支持本地存储、Git 和 Subversion 的可插拔存储库层。

在这个项目中,我使用 native profile,它只是从本地类路径加载配置文件。您可以在配置服务资源中看到 shared目录 。现在,当 Notification-service 请求它的配置时,Config 服务使用 and 响应 (在所有客户端应用程序之间共享)。shared/notification-service.ymlshared/application.yml

客户端使用

只需构建具有 spring-cloud-starter-config 依赖关系的 Spring Boot 应用程序,其余的将由自动配置完成。

现在您的应用程序中不需要任何嵌入式属性。只需提供 bootstrap.yml 应用程序名称和配置服务 url:

spring:
  application:
    name: notification-service
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true

使用 Spring Cloud Config,您可以动态更改应用程序配置

例如, EmailService bean 用 @RefreshScope. 这意味着您可以更改电子邮件文本和主题行,而无需重新构建和重新启动通知服务应用程序。

首先,更改配置服务器中所需的属性。然后,对 Notification 服务执行刷新请求: curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh

您还可以使用webhook 自动执行此过程。

笔记

  • 但是动态刷新有一些限制。 @RefreshScope 不适用于 @Configuration 类,也不能影响 @Scheduled 方法。
  • fail-fast 属性意味着 Spring Boot 应用程序如果无法连接到 Config Service 将立即启动失败。当您同时启动所有应用程序时,这非常有用。
  • 下面有重要的安全说明。

认证服务

授权职责被完全提取到单独的服务器,它为后端资源服务授予OAuth2 令牌 。Auth Server 用于用户授权以及边界内的安全机器对机器通信。

在这个项目中,我将 Password credentials 其用作用户授权的授权类型(因为它仅由本机应用程序 UI 使用)和 Client Credentials 微服务授权的授权类型。

Spring Cloud Security 提供了方便的注解和自动配置,使得这在服务器端和客户端都非常容易实现。您可以在文档中了解有关它的更多信息, 并在Auth Server 代码 中查看配置详细信息 。

从客户端来看,一切都与传统的基于会话的授权完全相同。Principal 您可以使用基于表达式的访问控制和 @PreAuthorize 注释从请求中检索 对象、检查用户角色和其他内容。

PiggyMetrics 中的每个客户端(帐户服务、统计服务、通知服务和浏览器)都有一个范围: server用于后端服务,以及 ui - 用于浏览器。所以我们也可以保护控制器免受外部访问,例如:

PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {
    return statisticsService.findByAccountName(name);
}

网关 API

如您所见,共有三个核心服务,它们将外部 API 暴露给客户端。在现实世界的系统中,这个数字会像整个系统的复杂性一样快速增长。实际上,渲染一个复杂的网页可能涉及数百个服务。

理论上,客户端可以直接向每个微服务发出请求。但显然这个选项存在挑战和限制,比如必须知道所有端点地址,分别为每个信息和平执行 http 请求,在客户端合并结果。另一个问题是可能在后端使用的非网络友好协议。

通常更好的方法是使用 API 网关。它是系统的单一入口点,用于通过将请求路由到适当的后端服务或调用多个后端服务并 聚合结果来处理请求。此外,它还可用于身份验证、洞察力、压力和金丝雀测试、服务迁移、静态响应处理、主动流量管理。

Netflix 开源 了这样一个边缘服务,现在有了 Spring Cloud,我们可以通过一个 @EnableZuulProxy注解来启用它。在这个项目中,我使用 Zuul 来存储静态内容(UI 应用程序)并将请求路由到适当的微服务。这是通知服务的简单的基于前缀的路由配置:

zuul:
  routes:
    notification-service:
        path: /notifications/**
        serviceId: notification-service
        stripPrefix: false

这意味着所有以 开头的请求 /notifications 都将被路由到通知服务。如您所见,没有硬编码的地址。Zuul 使用服务发现机制来定位通知服务实例以及断路器和负载均衡器,如下所述。

服务发现

另一种常见的架构模式是服务发现。它允许自动检测服务实例的网络位置,这些实例可能由于自动缩放、故障和升级而具有动态分配的地址。

服务发现的关键部分是注册表。我在这个项目中使用了 Netflix Eureka。Eureka 是客户端发现模式的一个很好的例子,当客户端负责确定可用服务实例的位置(使用注册表服务器)并在它们之间平衡请求时。

spring-cloud-starter-eureka-server 使用 Spring Boot,您可以使用依赖项、 @EnableEurekaServer 注释和简单的配置属性轻松构建 Eureka Registry 。

客户端支持通过 @EnableDiscoveryClient 注释和 bootstrap.yml 应用程序名称启用:

spring:
  application:
    name: notification-service

现在,在应用程序启动时,它将注册到 Eureka Server 并提供元数据,例如主机和端口、健康指标 URL、主页等。Eureka 从属于服务的每个实例接收心跳消息。如果心跳在可配置的时间表上失败,则将从注册表中删除该实例。

此外,Eureka 提供了一个简单的界面,您可以在其中跟踪正在运行的服务和可用实例的数量: http://localhost:8761

负载均衡器、断路器和 Http 客户端

Netflix OSS 提供了另一套很棒的工具。

丝带

Ribbon 是一个客户端负载均衡器,可让您对 HTTP 和 TCP 客户端的行为进行大量控制。与传统的负载均衡器相比,每次在线调用都不需要额外的跃点——您可以直接联系所需的服务。

开箱即用,它与 Spring Cloud 和 Service Discovery 原生集成。Eureka Client 提供了可用服务器的动态列表,因此 Ribbon 可以在它们之间进行平衡。

海斯特里克斯

Hystrix 是断路器模式的实现,它可以控制通过网络访问的依赖项的延迟和故障。主要思想是在具有大量微服务的分布式环境中停止级联故障。这有助于快速失败并尽快恢复——自我修复的容错系统的重要方面。

除了断路器控制之外,您还可以使用 Hystrix 添加一个备用方法,在主命令失败时调用该方法以获得默认值。

此外,Hystrix 会为每个命令生成有关执行结果和延迟的指标,我们可以使用这些指标来监控系统行为。

学习资料

假装

Feign 是一个声明式 HTTP 客户端,与 Ribbon 和 Hystrix 无缝集成。实际上,通过一个 spring-cloud-starter-feign 依赖项和 @EnableFeignClients 注释,您就拥有了一整套负载均衡器、断路器和 HTTP 客户端,并具有明智的现成默认配置。

以下是 Account Service 的示例:

FeignClient(name = "statistics-service")
public interface StatisticsServiceClient {

    @RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    void updateStatistics(@PathVariable("accountName") String accountName, Account account);

}
  • 您需要的只是一个界面
  • @RequestMapping 您可以在 Spring MVC 控制器和 Feign 方法之间共享 部分
  • 上面的示例仅指定了所需的服务 id - statistics-service,这要归功于通过 Eureka 进行的自动发现(但显然您可以使用特定的 url 访问任何资源)

监控仪表板

在这个项目配置中,每个带有 Hystrix 的微服务都通过 Spring Cloud Bus(使用 AMQP 代理)将指标推送到 Turbine。Monitoring 项目只是一个带有Turbine和Hystrix Dashboard的小型 Spring boot 应用程序。

让我们看看我们的系统在负载下的行为:帐户服务调用统计服务,它以不同的模拟延迟响应。响应超时阈值设置为 1 秒。

"table" data-size="normal" data-row-style="normal">



日志分析

在尝试识别分布式环境中的问题时,集中式日志记录非常有用。Elasticsearch、Logstash 和 Kibana 堆栈可让您轻松搜索和分析您的日志、利用率和网络活动数据。我的另一个项目中描述了现成的 Docker 配置 。

安全

高级安全配置超出了此概念验证项目的范围。为了更真实地模拟真实系统,请考虑使用 https 和 JCE 密钥库来加密微服务密码和配置服务器属性内容(有关详细信息,请参阅文档 )。

基础设施自动化

部署相互依赖的微服务是一个比部署单体应用程序复杂得多的过程。拥有完全自动化的基础架构非常重要。我们可以通过持续交付方法获得以下好处:

  • 随时发布软件的能力。
  • 任何构建最终都可能成为发布。
  • 构建工件一次,根据需要进行部署。

这是一个简单的持续交付工作流程,在这个项目中实现:

在此 配置中,Travis CI 为每次成功的 Git 推送构建标记图像。因此, Docker Hublatest 上的每个微服务 始终有一个 镜像, 并且旧镜像使用 Git 提交哈希进行标记。如果需要,可以轻松部署它们中的任何一个并快速回滚。
如何运行所有的东西?
这真的很容易,我建议你尝试一下。请记住,您将启动 8 个 Spring Boot 应用程序、4 个 MongoDB 实例和 RabbitMq。确保您 4 Gb 的机器上有可用的 RAM。您始终可以通过 Gateway、Registry、Config、Auth Service 和 Account Service 运行重要的服务。
在你开始前

  • 安装 Docker 和 Docker Compose。
  • 导出环境变量: CONFIG_SERVICE_PASSWORDNOTIFICATION_SERVICE_PASSWORDSTATISTICS_SERVICE_PASSWORDACCOUNT_SERVICE_PASSWORDMONGODB_PASSWORD

生产模式
在这种模式下,所有最新的镜像都将从 Docker Hub 中拉取。只需复制 docker-compose.yml 并点击 docker-compose up -d
发展模式
如果您想自己构建图像(例如,对代码进行一些更改),您必须克隆所有存储库并使用 Maven 构建工件。然后,运行 docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
docker-compose.dev.yml 继承 docker-compose.yml 了在本地构建图像并公开所有容器端口以方便开发的额外可能性。
重要端点

  • 本地主机:80 - 网关
  • 本地主机:8761 - 尤里卡仪表板
  • 本地主机:9000 - Hystrix 仪表板
  • localhost:8989 - 涡轮流(Hystrix Dashboard 的来源)
  • localhost:15672 - RabbitMq 管理

笔记
所有 Spring Boot 应用程序都需要已经运行Config Server 才能启动。但是由于 fail-fast Spring Boot 属性和 restart: always docker-compose 选项,我们可以同时启动所有容器。这意味着所有依赖容器都将尝试重新启动,直到 Config Server 启动并运行。
此外,服务发现机制在所有应用程序启动后都需要一些时间。在实例、Eureka 服务器和客户端在其本地缓存中都有相同的元数据之前,客户端无法发现任何服务,因此可能需要 3 次心跳。默认心跳周期为 30 秒。

说明:本文限于篇幅,故而只展示部分的面试内容,完整的Java面试学习文档小编已经帮你整理好了,有需要的朋友点赞+关注私信我777免费领取Java、大厂面试学习资料哦!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值