微服务架构设计模式-第十三章(完结)

第13章 微服务架构的重构策略

绞杀者模式

13.1 重构到微服务需要考虑的问题

13.1.1 为什么要重构单体应用

  • 交付缓慢
  • 充满故障的软件交付
  • 可扩展性差

理解这些问题的存在是非常重要的。因为这表明应用的需求已经超过了当前架构的承载能力。缓慢交付和错误百出的交付的常见原因是软件开发流程不佳(而不是架构的原因)。例如,如果你仍然依赖于手动测试,那么(在不更改架构的情况下)开始采用自动化测试可以显著提高开发速度。同样,你有时可以在不改变架构的情况下解决可扩展性问题。应该首先尝试更简单的解决方案。如果尝试了这些之后,仍然存在软件交付问题,那么就应该认真考虑迁移到微服务架构。我们来看看如何做到这一点。

13.1.2 绞杀单体应用

不要做 "一步到位,推倒重来" 式的改造

martin fowler:推到重写的唯一保证,就是彻底搞砸一切

76-绞杀者模式
尽早并且频繁地体现出价值

先将应用程序的高价值部分迁移到微服务架构。有助于获得业务团队对重构工作的支持。

尽可能少对单体做出修改

部署基础设施,这对你来说还为时过早

建议只在架构重构的前期进行最小的投资。唯一不可或缺的是执行自动化测试的部署流水线

建议退出任何涉及重大投资的技术基础设施决策,直到你获得开发微服务架构应用的实际经验。只有在运行一些服务后,你才会有经验选择技术基础设施

13.2 将单体应用重构为微服务架构的若干策略

  • 将新功能实现为服务
  • 隔离表现层和后端
  • 通过将功能提取到服务中来分解单体

第一种策略阻止了单体的发展。它通常是一种快速展示微服务价值的方法,有助于让迁移和重构的工作获得公司内部各个层面支持。另外两种策略打破了单体。在重构单体时,你有时可能会使用第二种策略,但你肯定会使用第三种策略,因为它能实现将功能从单体迁移到绞杀者应用程序中。

13.2.1 将新功能实现为服务

把新的服务与单体集成

  • api gateway:将对新功能的请求路由到新服务,并将遗留请求路由到单体
  • 集成胶水代码:将服务和单体结合。它使服务能够访问单体所拥有的数据,并能够调用单体实现的功能。

集成胶水的代码不是一个独立组件。相反,它由单体中的适配器和使用一个或多个进程间通信机制的服务组成

何时把新功能实现为服务

并非每个新功能都可以作为服务实现(新增字段,紧耦合,过多的进程间通信导致性能下降,数据一致性问题)

如果新功能无法作为服务实现,则解决方案通常是首先在单体中实现新功能。之后,可以将该功能以及其他相关功能提取到自己的服务中

13.2.2 隔离表现层与后端

  • 表现逻辑层:HTML 页面
  • 业务逻辑层:
  • 数据访问逻辑层

13.2.3 提取业务能力到服务中

  • 实现 API 端点的入站适配器
  • 领域逻辑
  • 出站适配器,例如数据库访问逻辑
  • 单体的数据库模式

提取服务具有挑战性。你需要确定如何将单体的领域模型分成两个独立的领域模型,其中一个模型成为服务的领域模型。你需要打破对象引用等依赖。你甚至可能需要拆分类,以将功能移动到服务中。对了,你还需要重构数据库。

提取服务通常很耗时,尤其是当单体的代码库很混乱时。因此,你需要仔细考虑要提取的服务。应当重点关注重构那些能够提高很多价值的应用程序部分。在提取服务之前,问问自己这样做的好处是什么。

提取服务时会遇到以下这些挑战:

  • 拆解领域模型
  • 重构数据库

https://book.douban.com/subject/6523996/ 数据库重构

复制数据以避免更广泛的更改

77-复制数据库数据
确定提取何种服务以及何时提取

一种策略是有效地冻结单体架构的开发并按需提取服务。可以提取必要的服务并进行更改,而不是在单体中实现功能或修复错误。

另一种策略是更有计划的方法,根据提取的预期收益,对应用程序的模块进行排名

  • 加速开发
  • 解决性能、可扩展性或可靠性问题
  • 允许提取其他一些服务

13.3 设计服务与单体的协作方式

13.3.1 设计集成胶水

集成胶水由服务和单体中的代码组成,它们使用某种进程间通信机制。集成胶水的设计取决于所使用的进程间通信机制的类型。

设计集成胶水的 API

选择交互方式和进程间通信机制

如果一方需要查询另一方拥有的数据,有几种选择。一种是实现存储库接口的适配器,以调用数据提供者的 API。此 API 通常使用请求/响应的交互方式,如 REST 或 grpc

好处:简单

弊端:效率低下,降低可用性(同步)

还有一种方法是让数据使用者维护数据的副本(本质上是 CQRS 视图)

实现反腐层(anti corruption layer,ACL)

用于在两个不同的领域模型之间进行转换,防止一个模型的概念污染另一个模型

单体如何发布和订阅领域事件

  • 使用与服务相同的领域事件发布机制(弊端:定位所有位置并插入调用以发布事件可能非常耗时且容易出错)
  • 在数据库级别发布领域事件(使用事务逻辑拖尾或轮询)
    • 好处:不必更改单体
    • 弊端:很难确定更新的原因,并发布适当的、高阶的业务事件
  • 使用框架

13.3.2 在服务和单体之间维持数据一致性

saga

修改单体应用使其支持补偿事务的挑战

saga 并不总是要求单体应用支持补偿事务

如果每个单体的事务都是一个关键性事务或一个可重复性事务,那么单体就永远不需要执行补偿事务。因此,你只需要对单体进行最小的更改即可支持 saga

选择合适的服务提取顺序,以避免在单体中实现补偿事务

13.3.3 处理身份验证和访问授权

对单体的登录请求处理程序进行一次小的更改。登录处理程序返回一个额外的 cookie,本例中我称为 userinfo,其中包含用户信息,例如用户 id 和角色。浏览器在每个请求中都包含该 cookie。api gateway 从 cookie 中提取信息,并将其包含在它向服务提供的 HTTP 请求中。因此,每个服务都可以访问所需的用户信息。

78-userInfo

13.4 将新功能实现为服务:处理错误配送订单

略

13.4.1 Delayed Delivery Service的设计

13.4.2 为Delayed Delivery Service设计集成胶水

13.5 从单体中提取送餐管理功能

略

13.5.1 现有的送餐管理功能

13.5.2 Delivery Service概览

13.5.3 设计Delivery Service的领域模型

13.5.4 Delivery Service集成胶水的设计

13.5.5 修改FTGO单体使其能够与Delivery Service交互


🌸🌸🌸🌸🌸🌸🌸完结撒花🌸🌸🌸🌸🌸🌸🌸🌸

posted @ 2026-10-11 07:48  LHX2018  阅读(3)  评论(0)    收藏  举报