博客 | NGINX

将整体式架构重构为微服务

NGINX-F5-horiz-black-type-RGB 的一部分
克里斯·理查森缩略图
克里斯·理查森
2016 年 3 月 8 日发布

编辑– 本系列文章共七部分,现已完成:

  1. 微服务简介
  2. 构建微服务: 使用 API 网关
  3. 构建微服务: 微服务架构中的进程间通信
  4. 微服务架构中的服务发现
  5. 微服务的事件驱动数据管理
  6. 选择微服务部署策略
  7. 将整体式架构重构为微服务(本文)

您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署。 并参阅我们关于微服务参考架构微服务解决方案页面的系列文章。

这是我的关于使用微服务构建应用的系列文章的第七篇也是最后一篇。 第一篇文章介绍了微服务架构模式,并讨论了使用微服务的优点和缺点。 以下文章讨论了微服务架构的不同方面:使用 API 网关<.htmla>、进程间通信服务发现事件驱动的数据管理部署微服务。 在本文中,我们研究将单体应用迁移到微服务的策略。

我希望本系列文章能让您很好地了解微服务架构、其优点和缺点以及何时使用它。 也许微服务架构非常适合您的组织。

然而,您很有可能正在开发大型、复杂的单片应用。 您每天开发和部署应用的经历是缓慢而痛苦的。 微服务似乎是一个遥远的涅槃。 幸运的是,你可以采用一些策略来逃离整体地狱。 在本文中,我描述了如何逐步地将单片应用重构为一组微服务。

微服务重构概述

将单体应用转变为微服务的过程是应用现代化的一种形式。 这是开发人员几十年来一直在做的事情。 因此,在将应用重构为微服务时,我们可以重复使用一些想法。

不应使用的策略之一是“大爆炸”重写。 那时您将集中所有开发精力从头开始构建一个基于微服务的新型应用。 虽然听起来很有吸引力,但风险极大,而且很可能会以失败告终。 据报道,马丁·福勒曾说过:“大爆炸重写版唯一能保证的就是大爆炸!”

你不应该进行“大爆炸”式的重写,而应该逐步重构你的单片应用。 您逐步构建一个由微服务组成的新应用,并将其与您的单片应用一起运行。 随着时间的推移,单片应用实现的功能数量会逐渐减少,直到完全消失或仅仅变成另一个微服务。 这种策略类似于在以 70 英里/小时的速度在高速公路上行驶时对汽车进行维修——虽然具有挑战性,但比尝试大爆炸重写的风险要小得多。

Martin Fowler 将这种应用现代化策略称为Strangler Application 。 该名字来源于热带雨林中发现的绞杀藤(又名绞杀无花果)。 绞杀藤生长在树木周围,以便获取森林树冠上方的阳光。 有时,树会死亡,留下树形的藤蔓。 应用现代化遵循相同的模式。 我们会围绕遗留应用构建由微服务组成的新应用,而新应用程序最终会消亡。

让我们看看实现这一目标的不同策略。

策略 1——停止挖掘

洞穴定律说,无论何时,当你身处洞穴时,你就应该停止挖掘。 当您的单片应用变得难以管理时,这是一个很好的建议。 换句话说,你应该停止把整体式架构变得更大。 这意味着当您实现新功能时,您不应该向整体式应用程序添加更多代码。 相反,此策略的主要思想是将新代码放入独立的微服务中。 下图显示了应用此方法后的系统架构。

除了新服务和遗留整体之外,还有另外两个组件。 第一个是请求路由器,它处理传入的(HTTP)请求。 它与之前的文章<.htmla>中描述的API网关类似。 路由器将与新功能对应的请求发送到新服务。 它将遗留请求路由至整体式架构。

另一个组件是粘合代码,它将服务与整体式应用程序集成在一起。 服务很少单独存在,并且经常需要访问整体所拥有的数据。 粘合代码位于整体式应用程序、服务或两者中,负责数据集成。 该服务使用粘合代码来读取和写入整体式架构所拥有的数据。

服务可以使用三种策略来访问整体式应用程序的数据:

  • 调用整体式架构提供的远程 API
  • 直接访问整体式架构的数据库
  • 维护自己的数据副本,与单体应用的数据库同步

粘合代码有时被称为防腐层。 这是因为粘合代码可以防止具有自己的原始领域模型的服务受到遗留整体领域模型的概念的污染。 粘合代码在两个不同的模型之间进行转换。 反腐层这个术语最早出现在Eric Evans所著的必读书籍《领域驱动设计》中,随后在一份白皮书中得到细化。 建立反腐败层并非易事。 但如果你想摆脱单一地狱,创建一个这样的系统是至关重要的。

将新功能作为轻量级服务实现有几个好处。 它可以防止整体变得更加难以管理。 该服务可以独立于整体式架构进行开发、部署和扩展。 对于您创建的每个新服务,您都可以体验到微服务架构带来的好处。

然而,这种方法对于解决整体问题毫无作用。 为了解决这些问题,你需要打破整体。 让我们看看实现这一目标的策略。

策略 2——拆分前端和后端

缩小单片应用的一个策略是表示层与业务逻辑层和数据访问层分离。 典型的企业应用至少由三种不同类型的组件组成:

  • 表示层 – 处理 HTTP 请求并实现 (REST) API 或基于 HTML 的 Web UI 的组件。在具有复杂用户界面的应用中,表示层通常是大量代码。
  • 业务逻辑层 – 作为应用核心并实现业务规则的组件。
  • 数据访问层——访问数据库和消息代理等基础设施组件的组件。

通常,一边是表示逻辑,另一边是业务和数据访问逻辑,这两者之间有明确的区分。 业务层具有由一个或多个外观组成的粗粒度 API,它封装了业务逻辑组件。 此 API 是一个自然的接缝,您可以沿着它将整体分成两个较小的应用。 一个应用包含表示层。 另一个应用包含业务和数据访问逻辑。 拆分后,表示逻辑应用对业务逻辑应用进行远程调用。 下图显示了重构前后的架构。

以这种方式拆分整体有两个主要好处。 它使您能够彼此独立地开发、部署和扩展两个应用。 特别是,它允许表示层开发人员在用户界面上快速迭代并轻松执行 A/B 测试等。 这种方法的另一个好处是它公开了一个可由您开发的微服务调用的远程 API。

但这一策略仅是一个部分解决方案。 其中一个或两个应用很有可能会成为难以管理的整体。 您需要使用第三种策略来消除剩余的一个或多个整体。

策略 3——提取服务

第三个重构策略是将整体式架构中现有的模块转变为独立的微服务。 每次提取一个模块并将其转变为一项服务时,整体结构就会缩小。 一旦您转换了足够多的模块,整体式架构就不再是问题了。 它要么完全消失,要么变得足够小,只是另一项服务。

确定将哪些模块转换为服务的优先级

大型、复杂的单片应用由数十或数百个模块组成,所有模块都是提取的候选。 弄清楚首先要转换哪些模块通常很困难。 一个好的方法是从几个易于提取的模块开始。 这将使您获得有关微服务的总体经验以及具体的提取过程的经验。 之后,您应该提取那些能给您带来最大益处的模块。

将模块转换为服务通常很耗时。 您希望根据您将获得的益处对模块进行排名。 提取经常变化的模块通常是有益的。 一旦将模块转换为服务,您就可以独立于整体进行开发和部署它,这将加速开发。

提取资源需求与整体其余部分有显著差异的模块也是有益的。 例如,将具有内存数据库的模块转换为服务很有用,然后可以将其部署在具有大量内存的主机上。 类似地,提取实现计算成本高昂的算法的模块也是值得的,因为服务随后可以部署在具有大量 CPU 的主机上。 通过将具有特定资源需求的模块转变为服务,您可以使您的应用更易于扩展。

当确定要提取哪些模块时,寻找现有的粗粒度边界(又称接缝)很有用。 它们使得将模块转化为服务变得更容易、更便宜。 这种边界的一个例子是仅通过异步消息与应用的其余部分进行通信的模块。 将该模块转变为微服务相对便宜且容易。

如何提取模块

提取模块的第一步是定义模块和整体之间的粗粒度接口。 它很可能是一个双向 API,因为整体式架构需要服务拥有的数据,反之亦然。 由于模块与应用其余部分之间存在复杂的依赖关系和细粒度的交互模式,实现这样的 API 通常具有挑战性。 使用领域模型模式实现的业务逻辑尤其难以重构,因为领域模型类之间存在大量关联。 您经常需要进行重大的代码更改来打破这些依赖关系。 下图显示了重构过程。

一旦实现了粗粒度接口,就可以将模块转变为独立的服务。 为此,您必须编写代码以使整体式应用程序和服务能够通过使用进程间通信(IPC) 机制的 API 进行通信。 下图展示了重构之前、重构期间和重构之后的架构。

在此示例中,模块 Z 是需要提取的候选模块。 它的组件被模块 X 使用,并且它使用模块 Y。重构的第一步是定义一对粗粒度的 API。 第一个接口是模块 X 用于调用模块 Z 的入站接口。第二个接口是模块 Z 用于调用模块 Y 的出站接口。

第二个重构步骤将模块转变为独立服务。 入站和出站接口由使用IPC机制的代码实现。 您很可能需要通过将模块 Z 与处理服务发现等跨切关注点的微服务机箱框架相结合来构建服务。

一旦提取了一个模块,您就拥有了另一项可以独立于整体和任何其他服务进行开发、部署和扩展的服务。 您甚至可以从头开始重写服务;在这种情况下,将服务与整体集成的 API 代码将成为在两个领域模型之间进行转换的反腐败层。 每次提取一个服务,你就向微服务的方向迈出了一步。 随着时间的推移,整体式架构将会缩小,而微服务的数量则会不断增加。

概括

将现有应用迁移到微服务的过程是应用现代化的一种形式。 您不应该通过从头开始重写应用来转向微服务。 相反,您应该逐步将应用重构为一组微服务。 您可以使用三种策略:将新功能实现为微服务;表示组件与业务和数据访问组件分离;以及将整体中的现有模块转换为服务。 随着时间的推移,微服务的数量将会增长,开发团队的敏捷性和速度也会提高。

编辑– 本系列文章共七部分,现已完成:

  1. 微服务简介
  2. 构建微服务: 使用 API 网关
  3. 构建微服务: 微服务架构中的进程间通信
  4. 微服务架构中的服务发现
  5. 微服务的事件驱动数据管理
  6. 选择微服务部署策略
  7. 将整体式架构重构为微服务(本文)

您还可以下载完整的文章集,以及有关使用 NGINX Plus 实现微服务的信息,作为电子书 -微服务: 从设计到部署。 并参阅我们关于微服务参考架构微服务解决方案页面的系列文章。

客座博主 Chris Richardson 是原CloudFoundry.com的创始人,该网站是针对 Amazon EC2 的早期 Java PaaS(平台即服务)。 他现在为各组织提供咨询服务,以改进他们开发和部署应用的方式。 他还定期在https://microservices.io上撰写有关微服务的博客


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”