《微服务架构设计模式》读书总结
《微服务架构设计模式》这本书介绍了引入微服务架构后面临的挑战,提供了一些模式用于应对这些挑战。所有的模式都可以在 作者的网站上找到,书上只是使用了更加具体的例子和更详细的语言来阐述而已。
本文是个人的读书总结,不是系统的知识梳理,慎读。
模式
为了解决特定条件下的问题的固定解决方案称为模式。
另一个词,模式语言 是指在特定领域内相关的模式的集合。
在模式这个概念中,还有一些关键点
需求
指必须解决的问题
描述了必须解决的问题和围绕这个问题的特定上下文
结果上下文
描述采用模式后可能带来的后果
好处
这个模式解决的问题
弊端
这个模式没有解决的问题
问题
这个模式带来的新问题
相关模式 指与其他模式的关系
前导模式
催生这个模式解决的需求的模式。换句话说,采用了一个模式的前导模式,可能还有没解决的问题或新引入的问题,这些问题可以通过这个模式解决。
后续模式
与前导模式相对应
替代模式
可以替换当前模式的模式
泛化模式
针对某种问题的一般性解决方案
特化模式
针对特定问题的解决方案
上面这些概念,化成思维导图:
了解了模式这个概念之后,再去看所有的微服务架构的设计模式,就能够建立起一个知识网络,把这些模式关联起来,知道什么样的问题可以使用哪个或哪些模式来解决。
微服务的模式语言
作者在书中将微服务的模式语言分为了三类:应用相关
、应用基础设施相关
、基础设施相关
,而这三类模式都是 微服务架构模式
的后续模式。这三类下还有更细粒度的划分,一点一点来看。
我不会完全按照作者的小类属于某个大类来划分,我会按照面临的问题来划分模式语言,有的模式可能出现在多个问题的解决方案中。
服务拆分相关
这一小类被划分到了 应用相关
下,包括了两种模式:根据业务能力进行拆分
和 根据子域进行拆分
。
这两个模式涉及到了 业务能力
和 子域
两概念,要理解这两个模式就要先理解这两个概念。
业务能力:能够为公司产生价值的商业活动。
子域:来自
DDD
,将领域划分后的产物,一般认为一个子域就会被设计为一个服务。
业务能力这个词,对我来讲太抽象,个人理解是使用在没有采用 DDD
的环境中的替代子域的方案。而 DDD
至少实践过,也有理论支持。
这两个模式互为替代模式。
进程间通信相关
将微服务拆分为单体后,面临的第一个问题就是服务间的访问问题,毕竟需要不同的服务相互协作,才能完成所有的业务。
要解决进程间通信的问题,首先要解决的问题就是进程在哪里。
服务发现
服务发现就是解决进程在哪里的问题,他的解决方案又可以分为 应用层服务发现
和 平台层服务发现
。它们一个需要自己写代码或使用第三方类库来实现,一个需要部署平台来实现,而它们又都是两个模式的组合使用来实现的。
应用层服务发现
自注册模式
客户端发现模式
平台层服务发现
第三方注册模式
服务器发现模式
它们的典型代表分别是 Netflix 的 Eureka 和 Kubernates。这两种组合的模式互为替换模式。
服务间通信方式
解决了服务发现的问题之后,服务就能找到想要通信的服务在哪里,那么就要解决真正的通信问题。
这个问题又可以分为 同步的远程调用
和 异步的远程调用
。
异步的方式,只有 消息模式
可以选择。
同步的方式,也只有 远程过程调用模式
,但实现方式却多种多样。比如 REST
、 gRPC
等等。但同步又会引入新的问题,那就是调用有可能失败。
针对失败的情况,可以使用 断路器模式
实现服务降级来应对。
同步的模式与异步的模式互为替换模式,一般会根据业务需求来进行选择。
数据一致性问题
数据一致性问题算是分布式应用的一大痛点。目前的解决方案有 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 等等一系列的模式都需要准备好,这样新加入的服务才能和单体一起工作。但这也不是绝对的,也可以逐渐演进,而不用一步到位。