这是本书中关于用微服务构建应用程序的第七章,也是最后一章。第一章介绍了微服务架构模式,并讨论了使用微服务的优点和缺点。接下来的章节讨论了使用微服务架构的各个方面:使用一个API网关,内部进程通信,服务发现,事件驱动数据管理,和部署微服务。在这章,我们将看看将单体应用移植到微服务的策略。
我希望这本电子书能让你很好地理解微服务架构、它的优缺点以及何时使用它。也许微服务体系结构非常适合您的组织。
但是,您很有可能正在处理大型,复杂的整体式应用。开发和部署应用程序的日常体验既缓慢又痛苦。微服务似乎是一个遥远的涅槃。幸运的是,您可以使用一些策略来逃离单体应用的地狱。在本文中,我将介绍如何将整体式应用程序增量重构为一组微服务。
重构微服务预览
将整体式应用程序转换为微服务的过程是应用程序现代化的一种形式。这是开发人员几十年来一直在做的事情。因此,在将应用程序重构为微服务时,我们可以借鉴一些方法。
首先不能使用的策略是"大爆炸"重写。这时,您将所有开发工作都集中在从头开始构建基于微服务的新应用程序上。虽然这听起来很吸引人,但它风险极大,很可能会以失败告终。正如马丁·福勒(Martin Fowler)所说,“大爆炸重写唯一能保证的就是大爆炸!”
替代大爆炸重写(Big Bang rewrite),你应当逐步重构你的单体应用(monolithic application).你组件添加新的功能,以微服务的形式,基于现有的功能创建扩展。以互补的方式修改你的单体应用,并同时运行微服务和修改后的整体架构。随着时间的推移,整体式应用程序实现的功能量会缩小,直到它完全消失或变成另一个微服务。这种策略类似于在高速公路上以70英里/小时的速度行驶时为您的汽车提供服务,但风险低于尝试大爆炸重写。
Martin Fowler 将这种应用程序现代化战略称为扼杀者应用(Strangler Application)。这个名字来自在热带雨林中发现的扼杀藤蔓(又名扼杀者无花果)。扼杀者藤蔓生长在一棵树周围,以便到达森林树冠上方的阳光。有时,树会死亡,留下树形藤蔓 应用程序现代化遵循相同的模式。我们将围绕旧版应用程序构建一个由微服务组成的新应用程序,这些应用程序将缩小,最终可能会消亡。
让我们看一下执行此操作的不同策略。
策略1:停止挖掘
洞定律说,每当你在洞里时,你应该停止挖掘。当您的整体式应用程序变得难以管理时,这是一个很好的建议。换句话说,你应该停止使整体变大。这意味着在实现新功能时,不应向整体式架构添加更多代码。相反,此策略的一大想法是将新代码放在独立的微服务中。
图7-1显示了在应用这种方法之后的系统架构。
除了新服务和旧版整体式之外,还有另外两个组件,第一个是请求路由器,用于处理传入(HTTP)请求。它类似于第 2 章中介绍的 API 网关。
路由器发送对应于新的请求到新功能。它将旧版请求路由到整体式架构。
另一个组件是粘附代码(glue code),它将服务与整体式架构集成在一起,服务很少孤立存在,通常需要访问整体架构拥有的数据。驻留在整体式架构和/或服务中的粘附代码负责数据集成。该服务使用粘附代码读取和写入整体式架构拥有的数据。
服务可以使用三种策略来访问整体式架构的数据:
- 调用整体式架构提供的远程 API。
- 直接访问整体式架构的数据库。
- 维护自己的数据副本,该副本与整体式架构的数据库同步。
胶水代码有时称为防腐层(anti-corruption layer)。这是因为胶水代码可以防止具有自己原始域模型的服务受到传统整体架构域模型中的概念的污染。反腐败层一词首先出现在Eric Evans的必读书《领域驱动设计》中,然后在白皮书中进行了完善。开发反腐败层可能是一项不平凡的任务。但是,如果你想从单一的地狱中成长,那么创建一个是必不可少的。
将新功能实现为轻量级服务有几个好处。它可以防止整体变得更加难以管理。可以独立于整体式架构开发、部署和扩展服务。对于您创建的每个新服务,您将体验微服务体系结构的好处。
但是,此方法无法解决整体式结构的问题。要解决这些问题,您需要分解整体。让我们来看看这样做的策略。
策略2:前后端分离
缩小整体式应用程序的策略是将表示层与业务逻辑和数据访问层分开。典型的企业应用程序至少由三种不同类型的组件组成:
- 表示层(Presentation layer)-处理 HTTP 请求并实现 (REST) API 或基于 HTML 的 Web UI 的组件。在具有复杂用户界面的应用程序中,表示层通常是大量的代码。
- 业务逻辑层(Business logic layer)-作为应用程序核心并实现业务规则的组件。
- 数据访问层(Data-access layer)-访问基础结构组件(如数据库和消息代理)的组件。
一端的表示逻辑与另一端的业务和数据访问逻辑之间通常存在明显的分离。 业务层具有由一个或多个外观组成的粗粒度 API,这些外观封装了业务逻辑组件。此 API 是一个自然的接缝,您可以沿着它把整体架构拆分为两个较小的应用程序 一个应用程序包含表示层,另一个应用程序包含业务和数据访问逻辑。拆分后,表示逻辑应用程序对业务逻辑应用程序进行远程调用。
图7-2显示了重构之前和之后的架构:
以这种方式拆分整体式结构有两个主要好处。它使您能够独立地开发、部署和扩展这两个应用程序。特别是,它允许表示层开发人员在用户界面上快速迭代并轻松执行A|B 测试。例如,此方法的另一个优点是它公开了远程 API。可由您开发的微服务调用。然而,这一战略只是部分解决办法。很可能两个应用程序中的一个或两个将是一个无法管理的单体,您需要使用第三个策略来消除剩余的一个单体或多个单体。
策略3:提取服务
第三种重构策略是将整体架构中的现有模块转换为独立的微服务。每次提取模块并将其转换为服务时,整体式架构就会缩小,一旦转换了足够多的模块,整体式将不再是问题, 要么完全消失,要么变得足够小,以至于它只是另一个服务。
确定要转换为服务的模块的优先级
大型、复杂的整体式应用程序由数十个或数百个模块组成,所有这些模块都是提取的候选模块。弄清楚首先要转换哪些模块通常具有挑战性。一个好的方法是从几个易于提取的模块开始。这将为您提供一般的微服务经验,特别是提取过程之后,您应该提取那些将为您带来最大好处的模块。
将模块转换为服务通常非常耗时,您希望按您将获得的好处对模块进行排名。提取频繁更改的模块通常是有益的。将模块转换为服务后,可以独立于整体式架构进行开发和部署,这将加速开发。
提取资源需求与整体架构其余部分的资源需求明显不同的模块也是有益的。例如,将具有内存中数据库的模块转换为服务非常有用,然后可以将服务部署在具有大量内存的主机(无论是裸机服务器、VM 还是云实例)上。同样,提取实现计算成本高昂的算法的模块是值得的,因为该服务可以部署在具有大量CPU的主机上。通过将具有特定资源要求的模块转换为服务,您可以使应用程序更轻松,扩展成本更低。
在确定要提取哪些模块时,查找现有的粗粒度边界(也称为接缝)很有用。它们使将模块转换为服务变得更加容易和便宜。这种边界的一个例子是一个模块,它只通过异步消息与应用程序的其余部分进行通信,将该模块转换为微服务可能相对便宜且容易。
如何提取模块
提取模块的第一步是在模块和整体式架构之间定义一个粗粒度接口。 它很可能是一个双向 API,因为整体式架构将需要服务拥有的数据,反之亦然。实现这样的 API 通常具有挑战性,因为模块和应用程序其余部分之间存在纠缠不清的依赖关系和细粒度的交互模式。使用域模型模式实现的业务逻辑在重构时尤其具有挑战性,因为域模型类之间存在大量关联。您通常需要进行重大的代码更改以打破这些依赖关系。图 7-3 显示了重构。
实现粗粒度接口后,即可将模块转换为独立服务。为此,必须编写代码以使整体架构和服务能够通过使用进程间通信 (IPC) 机制的 API 进行通信。图 7-3 显示了重构之前、期间和之后的体系结构。
在此示例中,模块 Z 是提取的候选模块,其组件由模块 X 使用,并且它使用模块 Y。第一个重构步骤是定义一对粗糙的 API。第一个接口是模块 X 用来调用模块 Z 的入站接口。第二个是模块 Z 用于调用模块 Y 的出站接口。
第二个重构步骤将模块转换为独立服务。入站和出站接口由使用 IPC 机制的代码实现。您很可能需要通过将模块 Z 与处理服务发现等跨领域问题的微服务机箱框架相结合来构建服务。
提取模块后,即可拥有另一个服务,该服务可以独立于整体架构和任何其他服务进行开发、部署和扩展。您甚至可以从头开始重写服务;
在这种情况下,将服务与整体式集成的 API 代码将成为在两者之间转换的反腐败层域模型。每次提取服务时,您都会朝着微服务的方向迈出另一步。随着时间的推移,整体式架构将缩小,您将拥有越来越多的微服务。
总结
将现有应用程序迁移到微服务的过程是应用程序现代化的一种形式,不应通过从头开始重写应用程序来迁移到微服务。相反,您应该以增量方式将应用程序重构为一组微服务。您可以使用三种策略:将新功能实现为微服务;将表示组件与业务和数据访问组件分开;并将整体式架构中的现有模块转换为服务。随着时间的推移,微服务的数量将会增长,开发团队的敏捷性和速度也会提高。
微服务实践:用NGINX驯服单体应用
如本章所述,将整体式架构转换为微服务可能是一个缓慢且具有挑战性的过程,但具有许多好处。使用NGINX,您可以在实际开始转换过程之前开始获得微服务的一些好处。
您可以通过将NGINX"放在"您现有的整体式应用程序前面来为迁移到微服务赢得大量时间。下面简要介绍了与微服务相关的优势:
-
更好的支持微服务 - 正如第5章侧边栏中提到的,NGINX,特别是NGINX Plus,具有有助于开发基于微服务的应用程序的功能,当您开始重新设计整体式应用程序时,由于NGINX中的功能,您的微服务将表现得更好,更易于管理。
-
跨环境的功能抽象 - 将功能作为反向代理服务器迁移到NGINX上,可以减少您在新环境中部署时会有所不同的内容,从您管理的服务器到各种类型的公共云,私有云和混合云。这补充并扩展了微服务固有的灵活性。
-
NGINX 微服务参考体系结构的可用性 - 当您迁移到NGINX时,你可以从 NGINX 微服务参考体系结构中借用,既可以在迁移到微服务后定义应用的最终结构,也可以根据需要为你创建的每个新微服务使用 MRA 的一部分。
总而言之,将NGINX作为过渡的第一步可以减轻整体式应用程序的压力,使其更容易获得微服务的所有好处,并为您提供用于过渡的模型。您可以了解有关MRA的更多信息,并立即获得NGINX Plus的免费试用版。