微服务架构设计模式-第十三章(完结)
第13章 微服务架构的重构策略
绞杀者模式
13.1 重构到微服务需要考虑的问题
13.1.1 为什么要重构单体应用
- 交付缓慢
- 充满故障的软件交付
- 可扩展性差
理解这些问题的存在是非常重要的。因为这表明应用的需求已经超过了当前架构的承载能力。缓慢交付和错误百出的交付的常见原因是软件开发流程不佳(而不是架构的原因)。例如,如果你仍然依赖于手动测试,那么(在不更改架构的情况下)开始采用自动化测试可以显著提高开发速度。同样,你有时可以在不改变架构的情况下解决可扩展性问题。应该首先尝试更简单的解决方案。如果尝试了这些之后,仍然存在软件交付问题,那么就应该认真考虑迁移到微服务架构。我们来看看如何做到这一点。
13.1.2 绞杀单体应用
不要做 "一步到位,推倒重来" 式的改造
martin fowler:推到重写的唯一保证,就是彻底搞砸一切

尽早并且频繁地体现出价值
先将应用程序的高价值部分迁移到微服务架构。有助于获得业务团队对重构工作的支持。
尽可能少对单体做出修改
部署基础设施,这对你来说还为时过早
建议只在架构重构的前期进行最小的投资。唯一不可或缺的是执行自动化测试的部署流水线
建议退出任何涉及重大投资的技术基础设施决策,直到你获得开发微服务架构应用的实际经验。只有在运行一些服务后,你才会有经验选择技术基础设施
13.2 将单体应用重构为微服务架构的若干策略
- 将新功能实现为服务
- 隔离表现层和后端
- 通过将功能提取到服务中来分解单体
第一种策略阻止了单体的发展。它通常是一种快速展示微服务价值的方法,有助于让迁移和重构的工作获得公司内部各个层面支持。另外两种策略打破了单体。在重构单体时,你有时可能会使用第二种策略,但你肯定会使用第三种策略,因为它能实现将功能从单体迁移到绞杀者应用程序中。
13.2.1 将新功能实现为服务
把新的服务与单体集成
- api gateway:将对新功能的请求路由到新服务,并将遗留请求路由到单体
- 集成胶水代码:将服务和单体结合。它使服务能够访问单体所拥有的数据,并能够调用单体实现的功能。
集成胶水的代码不是一个独立组件。相反,它由单体中的适配器和使用一个或多个进程间通信机制的服务组成
何时把新功能实现为服务
并非每个新功能都可以作为服务实现(新增字段,紧耦合,过多的进程间通信导致性能下降,数据一致性问题)
如果新功能无法作为服务实现,则解决方案通常是首先在单体中实现新功能。之后,可以将该功能以及其他相关功能提取到自己的服务中
13.2.2 隔离表现层与后端
- 表现逻辑层:HTML 页面
- 业务逻辑层:
- 数据访问逻辑层
13.2.3 提取业务能力到服务中
- 实现 API 端点的入站适配器
- 领域逻辑
- 出站适配器,例如数据库访问逻辑
- 单体的数据库模式
提取服务具有挑战性。你需要确定如何将单体的领域模型分成两个独立的领域模型,其中一个模型成为服务的领域模型。你需要打破对象引用等依赖。你甚至可能需要拆分类,以将功能移动到服务中。对了,你还需要重构数据库。
提取服务通常很耗时,尤其是当单体的代码库很混乱时。因此,你需要仔细考虑要提取的服务。应当重点关注重构那些能够提高很多价值的应用程序部分。在提取服务之前,问问自己这样做的好处是什么。
提取服务时会遇到以下这些挑战:
- 拆解领域模型
- 重构数据库
复制数据以避免更广泛的更改

确定提取何种服务以及何时提取
一种策略是有效地冻结单体架构的开发并按需提取服务。可以提取必要的服务并进行更改,而不是在单体中实现功能或修复错误。
另一种策略是更有计划的方法,根据提取的预期收益,对应用程序的模块进行排名
- 加速开发
- 解决性能、可扩展性或可靠性问题
- 允许提取其他一些服务
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 请求中。因此,每个服务都可以访问所需的用户信息。

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交互
🌸🌸🌸🌸🌸🌸🌸完结撒花🌸🌸🌸🌸🌸🌸🌸🌸

浙公网安备 33010602011771号