《微服务架构设计模式》读书总结

《微服务架构设计模式》这本书介绍了引入微服务架构后面临的挑战,提供了一些模式用于应对这些挑战。所有的模式都可以在 作者的网站上找到,书上只是使用了更加具体的例子和更详细的语言来阐述而已。

本文是个人的读书总结,不是系统的知识梳理,慎读

模式

为了解决特定条件下的问题的固定解决方案称为模式

另一个词,模式语言 是指在特定领域内相关的模式的集合。

在模式这个概念中,还有一些关键点

  • 需求

    指必须解决的问题

    描述了必须解决的问题和围绕这个问题的特定上下文

  • 结果上下文

    描述采用模式后可能带来的后果

    • 好处

      这个模式解决的问题

    • 弊端

      这个模式没有解决的问题

    • 问题

      这个模式带来的新问题

  • 相关模式 指与其他模式的关系

    • 前导模式

      催生这个模式解决的需求的模式。换句话说,采用了一个模式的前导模式,可能还有没解决的问题或新引入的问题,这些问题可以通过这个模式解决。

    • 后续模式

      与前导模式相对应

    • 替代模式

      可以替换当前模式的模式

    • 泛化模式

      针对某种问题的一般性解决方案

    • 特化模式

      针对特定问题的解决方案

上面这些概念,化成思维导图:

模式

了解了模式这个概念之后,再去看所有的微服务架构的设计模式,就能够建立起一个知识网络,把这些模式关联起来,知道什么样的问题可以使用哪个或哪些模式来解决。

微服务的模式语言

作者在书中将微服务的模式语言分为了三类:应用相关应用基础设施相关基础设施相关,而这三类模式都是 微服务架构模式 的后续模式。这三类下还有更细粒度的划分,一点一点来看。

我不会完全按照作者的小类属于某个大类来划分,我会按照面临的问题来划分模式语言,有的模式可能出现在多个问题的解决方案中。

服务拆分相关

这一小类被划分到了 应用相关 下,包括了两种模式:根据业务能力进行拆分根据子域进行拆分

这两个模式涉及到了 业务能力子域 两概念,要理解这两个模式就要先理解这两个概念。

  • 业务能力:能够为公司产生价值的商业活动。

  • 子域:来自 DDD,将领域划分后的产物,一般认为一个子域就会被设计为一个服务。

业务能力这个词,对我来讲太抽象,个人理解是使用在没有采用 DDD 的环境中的替代子域的方案。而 DDD 至少实践过,也有理论支持。

这两个模式互为替代模式。

进程间通信相关

将微服务拆分为单体后,面临的第一个问题就是服务间的访问问题,毕竟需要不同的服务相互协作,才能完成所有的业务。

要解决进程间通信的问题,首先要解决的问题就是进程在哪里。

服务发现

服务发现就是解决进程在哪里的问题,他的解决方案又可以分为 应用层服务发现平台层服务发现。它们一个需要自己写代码或使用第三方类库来实现,一个需要部署平台来实现,而它们又都是两个模式的组合使用来实现的。

  • 应用层服务发现

    • 自注册模式

    • 客户端发现模式

  • 平台层服务发现

    • 第三方注册模式

    • 服务器发现模式

它们的典型代表分别是 Netflix 的 Eureka 和 Kubernates。这两种组合的模式互为替换模式。

服务间通信方式

解决了服务发现的问题之后,服务就能找到想要通信的服务在哪里,那么就要解决真正的通信问题。

这个问题又可以分为 同步的远程调用异步的远程调用

异步的方式,只有 消息模式 可以选择。

同步的方式,也只有 远程过程调用模式,但实现方式却多种多样。比如 RESTgRPC 等等。但同步又会引入新的问题,那就是调用有可能失败。

针对失败的情况,可以使用 断路器模式 实现服务降级来应对。

同步的模式与异步的模式互为替换模式,一般会根据业务需求来进行选择。

数据一致性问题

数据一致性问题算是分布式应用的一大痛点。目前的解决方案有 2PC 模式Saga 模式。它们互为替换模式

其中的 Saga 模式 又可以采用 协同式编排式 来实现。

书中有详细讲述如何实现 Saga 模式

查询相关

微服务引入的另一个问题是,查询的时候,很难进行连表查询,因为数据被划分到了不同的数据库实例中,无法连接。

针对这个问题可以使用 API 组合CQRS 模式。

外部 API

对于来自微服务系统外的请求,如果让它直接到达服务本身,就会让外部实现和服务产生紧耦合,没有做到封装。

为了解决这个问题,可以使用 API Gateway 模式BFF 模式 来实现。

API Gateway 模式 是提供一个服务,对外只暴露这个服务,由这个服务来转发请求到真正的服务上。并且在这个 API Gateway 服务上,可以统一实现如认证授权、缓存等公共功能。

BFF 模式 是提供一个服务,编写一个 API 暴露到服务外部,屏蔽底层服务的 API 。外部服务调用的是 BFF 暴露的 API 。一般会针对不同类型的设备开发不同的 BFF 服务。

服务安全性

服务间访问时,如何辨别是谁在请求,是微服务引入的问题之一。

解决方案是 访问令牌模式。这里的令牌中包含了用户信息,帮助服务判断当前的访问者是谁、有没有权限执行请求。常见的令牌是 JWT

一般会选择使用 API Gateway 模式,在 API Gateway 服务上认证用户、颁发令牌。

可配置性

引入微服务后,会发现配置管理是一个问题,所以引入了 外部化配置模式 来解决它。

可观测性

这不仅仅是微服务的问题,只是在引入微服务后这个问题变得更大。针对不同的观测需求,需要采用不同的模式。

  • 健康检查 API 模式:查看服务是否在正常运行。

  • 日志聚合模式:在统一的地方查看所有服务的日志,而不需要到不同的地方查看。

  • 分布式追踪模式:在追踪一个请求时,因为请求会跨域多个服务,为了追踪整条请求链路而设计。

  • 应用程序指标模式:用于观测资源使用情况和告警。

  • 异常追踪模式:将异常发送到特定的服务,该服务对异常进行警报、管理等工作。

  • 审核日志记录模式:单体也需要。

服务基底模式

考虑到所有的服务都有一些公共功能,比如日志、分布式追踪、服务发现等等,使用某种基底模式可以简化服务的开发工作。

  • 微服务基底模式:将公共功能实现在框架上,在新加服务时,直接使用这个框架。

  • 服务网格模式:服务网格是一个网络层,由它来实现服务发现、负载均衡等问题。

  • 边车模式:边车是一个与服务同生同死的进程,由它来负责公共功能。

部署模式

这里的四种部署模式和微服务没有关系,单体应用也可以使用这些模式,这没有什么强制性。

  • 编程语言特定的发布包模式

  • 发布为虚拟机模式

  • 发布为容器模式

  • Serverless 部署模式

作者推荐的考虑顺序从下往上,但这仅仅是技术考虑的结果。实际选择时,还要考虑数据敏感性、部署环境技术限制等因素,Serverless 模式可能是最不会被选择的一个。

测试相关

测试方面面临的挑战主要是如何验证服务本身是工作的,以及如何验证服务间的集成是工作的。

针对第一个问题,可以使用 服务组件测试模式 来解决。其中的组件是指一个服务。在这样的测试中,对外部的调用将会被 mock,测试的关注点在于服务本身是否工作。

针对第二个问题,可以使用 消费者驱动的契约测试模式 来解决。一份契约,既可以在消费者端称为 stub,又可以在服务者端做为测试用例。

值得注意的是,即使上面两个测试都通过了,你仍然需要一个针对整个系统的 E2E 测试 ,才能保证系统是正常工作的。因为从测试金字塔来看,上面两个测试是在 E2E 测试 的下一层。

重构的模式

毕竟微服务都是拆出来的。实践微服务时,往往面临的问题是将一个巨大的单体服务拆分为微服务。针对这样的问题,就要祭出大名鼎鼎的 绞杀着模式

使用这个模式需要考虑三种策略:

  • 将新功能实现为服务

  • 隔离表现层与后端(本质上是指责分离)

  • 提取业务到服务中

当采用第一种和第三种策略时,都需要加入新的服务,那就需要准备好你的微服务需要的基础设施,也就是服务发现、API Gateway 等等一系列的模式都需要准备好,这样新加入的服务才能和单体一起工作。但这也不是绝对的,也可以逐渐演进,而不用一步到位。