从单体迁移到微服务的几种模式

标签: | 发表时间:2021-07-23 15:51 | 作者:
出处:https://www.infoq.cn

正确实现的微服务较单体应用有很多优势。许多组织都希望将他们的单体应用程序代码换成微服务代码。但事实证明,迁移到微服务并非易事。你应该问的第一个问题是,你真的需要微服务吗?单体存在的许多问题都可以使用模块化的单体架构轻松解决。一旦你确定自己真的需要微服务,就必须制定一套将单体应用转换为微服务的计划。本文介绍了一些模式,可以帮助你创建所需的计划。

 

在我们具体讨论这些拆分单体的模式之前,我们先来谈谈不应该做的一些事情。

不要做大爆炸重写


大爆炸重写(Big Bang Rewrite),顾名思义,是说我们必须在许多微服务中重写整个单体应用的代码,并一次性将它们都部署到生产环境中。Martin Fowler 说过的一句话非常正确:


大爆炸重写唯一能保证的就是大爆炸!


大爆炸重写都是很危险的。大爆炸重写需要漫长的开发时间,因为你必须对单体应用程序中的所有内容重新编码。此外,在微服务架构的开发过程中,你必须冻结单体应用中新的开发工作,因为单体应用中所做的所有更改都必须复制到微服务中。对于大多数公司来说,冻结应用程序开发工作可能存在风险,因为他们必须根据业务环境的变化随时调整软件。

 

对于一个组织来说,从单体逐渐转向微服务的路径一定是更好的选项。下面列举的一些可用设计模式可以帮助你逐步从单体架构转向微服务架构。

扼杀者(Strangler Fig)


扼杀者是 Martin Fowler 设计的一种模式。它的灵感来自于自然界的无花果。无花果是从自己寄生的树冠分枝开始生长的,其根向地面慢慢延伸。它的根会逐渐到达地面并继续生长,甚至在这一过程中会杀死寄主树。同样,在软件世界中,我们可以根据这种模式围绕单个单体应用程序来构建微服务。我们会在系统中逐步添加更多微服务,最终有一天会替换掉整个单体系统。

 

在扼杀者模式中,我们围绕现有单体架构的边缘创建新服务。单体的边缘是什么意思?我们通过具体的例子来深入理解。

图 1:单体应用

 

在图 1 中,你可以看到我们有一个单体应用程序。在上图中,产品库存、订单管理和计费管理模块位于应用程序的边缘。通知管理有多个来自应用程序内的入站调用。因此,我们无法将所有入站调用从外部应用程序重定向到通知管理。我们有另一种模式来将通知管理迁移到微服务,将在稍后讨论。

 

假设我们想将订单管理迁移到微服务。我们可以使用以下步骤。

 

  1. 插入代理:除非你已经有了一个代理,否则我们需要部署一个 HTTP 代理。在第 1 步中,我们部署一个 HTTP 代理,它将所有调用直接重定向到单体应用程序。引入 HTTP 代理后,你还可以了解网络上是否存在其他内容会延迟 API 调用。如果延迟很大,那么你必须先停止迁移并首先改进你的网络,然后再继续。

  2. 部署微服务:在第 2 步中,你将在生产环境中部署微服务。我们的微服务上不会有任何实时流量。在第 2 步中,我们将只测试微服务是否工作正常。

  3. 重定向流量:在第 3 步中,我们会将实际流量从 HTTP 代理重定向到我们新部署的微服务。如果出现问题,我们可以更改 HTTP 代理定向来轻松回滚。

 

所有步骤如图 2 所示。


抽象分支


当你需要提取其他模块所依赖的一个模块时,抽象分支的模式可能会很有用。假设在前面的示例中,我们想将通知管理转换为微服务。在这种情况下,我们就会使用抽象分支。我们需要执行以下步骤来提取模块。

 

  1. 创建抽象。你需要围绕要替换的模块创建抽象。

  2. 将现有功能的客户端更改为使用新抽象:你需要重构旧代码,让旧实现使用在步骤 1 中创建的抽象。

  3. 创建新的实现。你需要为功能创建一个新的微服务实现,将其部署到生产环境中并运行一些测试。

  4. 切换实现。当你运行了一些测试,有了一些信心后,你就可以切换到新的代码上。

  5. 清理。当你的微服务启动并运行后,最好清理旧代码库并删除旧模块。如果需要,你也可以删除抽象。在许多情况下,你之前创建的抽象只会改进你的代码库质量,这时完全可以保留它。

 

为了更好地理解整个过程,请参考图 3。


图 3:抽象分支

 

抽象分支模式可以用在很多地方。我们建议尽可能使用 Strangler Fig 而不是抽象分支。如果你确定你不能用 Stranger Fig 来将单体应用的某些部分替换为微服务,那么你就应该考虑抽象分支。

并行运行


无论你做了多少测试,出现错误的可能性仍然会存在。当你迁移一个关键系统时,你一点都不能指望运气。在这种情况下,并行运行模式可能会有所帮助。在这种模式中,我们会在生产环境部署我们新开发的微服务和旧的单体应用。我们会让数据流经两个系统。单体系统一开始会是唯一事实来源。我们将新开发的微服务的结果与单体结果做对比。如果我们发现存在任何不匹配情况,就要在微服务应用程序中修复它。一段时间后,当我们对新的微服务系统有足够的信心时,就可以停用单体应用的对应功能,并让微服务成为唯一事实来源。

 

在前面的例子中,假设我们想将计费管理从单体迁移到微服务。在这个模式下,我们将开发一个微服务并将相同的流量发送到我们新的微服务。每天结束时,我们可以用一个批处理作业来对比旧系统和新系统生成的账单是否相同。一旦我们有了足够的信心,就可以从单体应用中停用计费管理功能。我们还有一些开源库(比如 Github 的 scientist 库),可以帮助你更好地实现这种模式。

图 4:并行运行模式

 

当你的功能已经存在于单体应用中时,上面介绍的这种模式会很有用。假设你需要添加新的功能,比如你想在每次成功交易后通过电子邮件向用户发送下一次交易的折扣券。很简单,你只需在单体应用的订单模块中添加新代码即可调用新创建的折扣微服务。但是如果你没有代码呢?假设你正在使用其他供应商的解决方案,或正在使用某些 SAAS,你也依旧可以实现它。接下来的两种模式就是针对这种情况量身定制的。

装饰协作者(Decorating Collaborator)


这种模式的灵感来自我们熟悉和喜爱的一种模式——装饰者模式。在这种模式下,就像扼杀者模式一样,我们必须引入一个代理。我们让调用通过代理传递到单体应用,然后根据单体应用的响应,代理将调用我们新创建的微服务。

图 5:装饰协作者

 

图 5 展示了装饰协作者模式的机制。仅当微服务所需的所有数据都已存在于请求或响应中时,我们才应该使用这种模式。如果数据不存在,那么我们新创建的微服务就必须连接到单体数据库上。也就是说我们新的微服务需要与单体数据库耦合,这绝不是一个好主意。

更改数据捕获模式


在这种模式中,我们将对数据库中发生的更改做出反应。比方说,我们想为系统中创建的每个客户创建一张会员卡。在这种模式下,我们可以监听客户表中的更改。一旦我们检测到有新客户创建了客户表,我们就可以调用 Loyalty 微服务。然后这个微服务可以向客户发放会员卡,并向他们发送包含详细信息的电子邮件。你可以使用多种方法来监听数据库中的更改。你可以使用触发器,也可以使用数据库的事务日志。还可以编写一个每隔几分钟触发并检查数据库中发生的更改的流程。

总结


正确实现的微服务具有许多优势。将你的单体应用程序转换为微服务并不是朝夕就能完成的工作。你还应该记住,转换为微服务不是一场竞赛,而是一场漫长的马拉松。它需要足够的耐心,并且必须做出良好的架构决策才行。

 

在本文中,我们讨论了一些你可以使用的模式。大多数情况下,你需要应用多种模式才能将单体应用程序完全转换为微服务。最后,我只是建议,在迁移到微服务之前花点时间弄清楚你准备使用的策略,这种准备工作迟早会获得回报的。


参考资料:


https://martinfowler.com/bliki/StranglerFigApplication.html

https://martinfowler.com/bliki/BranchByAbstraction.html

 

英文原文链接:


https://levelup.gitconnected.com/patterns-to-know-before-migrating-your-monolith-to-microservices-72fcbcc7846e

相关 [单体 微服务 模式] 推荐:

从单体迁移到微服务的几种模式

- -
正确实现的微服务较单体应用有很多优势. 许多组织都希望将他们的单体应用程序代码换成微服务代码. 但事实证明,迁移到微服务并非易事. 你应该问的第一个问题是,你真的需要微服务吗. 单体存在的许多问题都可以使用模块化的单体架构轻松解决. 一旦你确定自己真的需要微服务,就必须制定一套将单体应用转换为微服务的计划.

微服务性能模式

- - 互联网 - ITeye博客
前言:基于微服务系统越来越普遍. 下面我们就来看看五种常见的特定微服务性能的挑战,以及如何应解他们. 背景:在IT界微服务架构为基础的系统越来越多, 每一个应用系统都集成了不同的组件和服务,几乎所有的特定业务应用程序都需要集成一个或更多的应用服务. 但是一个综合性系统集成不同的服务这无疑是一个巨大的挑战.

微服务之saga模式

- -
你已经使用 database ber service 模式. 每个service拥有自己的database. 一些业务事务会跨越多个service,所以你需要来确保data consistency. 例如,假设你正在构建一个电子商务网站,这个网站的用户的会有一个最大欠款限制,应用程序必须确保一个新订单不能超过用户的最大前款限制,但是orders表和customers表不在同一个数据库,所以应用程序不能简单的使用本地的ACID事务.

微服务的反模式和陷阱

- - 鸟窝
前几天我写了篇读书笔记: 《产品级微服务的八大原则》,介绍了Uber的SRE工程师 Susan J. Fowler 的免费书: Microservices in Production,文中提出了一个微服务成功与否的唯一标准就是可用性,非常有实践意义. 但是这本书偏向于从 SRE (site reliability engineer)的视角看待微服务,对于开发工程师 (SWE, software engineer)来说,更关注的是如何正确地从单体程序重构到微服务架构,或者从头设计微服务架构, 这篇读书笔记主要就是介绍这方面的实践和经验.

微服务的十个反模式和陷阱

- - 后端技术杂谈 | 飒然Hang
O’Reilly的电子书《Microservices AntiPatterns and Pitfalls》讲述了在微服务设计实现时十种最常见的反模式和陷阱. 书籍地址: https://www.oreilly.com/programming/free/microservices-antipatterns-and-pitfalls.csp,更全的反模式和陷阱可见作者的视频: http://oreil.ly/29GVuDG.

微服务分布式一致性模式 – ThoughtWorks洞见

- -
微服务拆分后遇到的一个麻烦是分布后的一致性问题. 单体架构的业务处理和数据都在一个进程里面,一致性保障很成熟,开发人员基本上不用关心. 当把业务系统拆分到不同进程时,就遇到了技术性一致性问题. 这带来了纠结,我们希望有一颗银弹,一把解决问题. 但由于分布式一致性在(CAP)理论上没有完美的解决方案,我们所能选择的方案是在特定业务场景下的选择.

[ 翻译 ] 微服务架构及设计模式

- -
本文介绍了主流常见的微服务模式. 因此,了解如何处理微服务架构(MSA)以及一些微服务设计模式,一个微服务架构的一些通用目标或者设计原则是很有价值的. 下面是在微服务架构方案中值得考虑的四个目标[1]. 1、缩减成本:MSA将会降低设计、实现和维护IT服务的总体成本. 2、加快发布速度:MSA将会加快服务从想法到部署的落地速度.

微服务架构设计模式 - XuMinzhe - 博客园

- -
单体地狱的银弹-微服务架构. 大型的复杂应用程序可以持续交付和持续部署. 每个服务都相对较小并容易维护. 分布式系统带来的各种复杂性. 开发者需要思考到底应该在应用的什么阶段使用微服务架构. 随着网络基础设施的高速发展,以及越来越多的个体接入互联网,在考虑构建支持海量请求以及多变业务的软件平台时,微服务架构成为多数人的首选.

微服务架构及设计模式 - DockOne.io

- -
【编者的话】本文作者详细介绍了微服务架构里一些常见的设计模式和它们各自的使用场景. 因此,了解如何处理微服务架构(MSA)以及一些微服务设计模式,一个微服务架构的一些通用目标或者设计原则是很有价值的. 下面是在微服务架构方案中值得考虑的四个目标. 缩减成本:MSA 将会降低设计、实现和维护IT服务的总体成本.

Serverless:微服务架构的终极模式

- - DockOne.io
微服务的生态和实践已经比较成熟,其设计方法、开发框架、CI/CD工具、基础设施管理工具等,都可以帮助企业顺利实施微服务. 然而,微服务远没有达到完美,它在架构、开发、基础设施方面仍然面临新的挑战. 微服务的粒度影响服务的交付速度及扩展性,微服务的开发引入治理组件,增加了开发的难度,以容器为基础的微服务基础设施在弹性等方面仍有不足,而微服务增加带来的基础设施成本也是微服务实施的新挑战.