如何将微服务应用于真实应用程序
标签: IBM Cloud,微服务
Kyle Brown
发布: 2017-03-29
您也许像我一样,不断地阅读有关新开发工具、新开发和操作实践,或者新架构原理的文章和博客。我们经常遇到的问题是,这些实践或架构原理可能在文章中看起来很不错,或者在全新的(绿地)应用程序中实现它们可能也很不错,但我们并不了解如何在现有应用程序中实现它们。
但是,在我们生活的世界中, 棕地 (brownfield) 应用程序(不是完全依据最新方法或使用最新工具构建的现有应用程序)更常见。在微服务架构中尤为如此。我交流过的大部分开发团队都觉得微服务听起来像是一个不错的主意,但他们不确定如何开始使用它们,因为他们目前使用的是大型整体式应用程序。
因此,要是能够找到一个真正在类似情形中有所帮助的解决方案就太好了,Martin Fowler 的 Strangler 应用程序模式 就是这样一个解决方案。尽管该模式是在他开发微服务架构之前编写的,但该模式给想要转向采用微服务方法的团队提供了很好的指导。
在 Martin Fowler 于 2004 年在 网站 上的发表的一篇文章中,他将 Strangler 应用程序模式定义为一种处理大型 Web 应用程序中的重构代码发布方式。
Strangler 应用程序基于一种藤蔓植物的类推假设,这种植物可以将它缠绕的树勒死。这里的设想是,您使用一种 Web 应用程序的结构 — 事实上 Web 应用程序是通过将功能映射到业务领域的不同方面的 URL 来构建的 — 将应用程序拆分为不同的功能领域,并一次一个领域地将这些领域替换为基于微服务的新实现。这会创建两个在同一个 URI 空间中并行运行的不同应用程序。随着时间的推移,重构的新应用程序会“勒死”或替代原始应用程序,最终使您能够停止使用旧的整体式应用程序。因此,Strangler 应用程序步骤包括 转换、 共存 和 消除:
- 转换 — 创建一个并行的新网站(例如,在 IBM Cloud 中或您的现有环境中,但基于更现代的方法)。
- 共存 — 暂时将现有站点留在原有的位置。从现有站点重定向到新站点,以便逐渐实现相应功能。
- 消除 — 随着流量从旧站点的一部分重定向到新站点,从现有站点中删除相应的旧功能(或者停止维护它)。
应用此模式的好处是,与尝试“大爆炸式”迁移(在发布任何新功能之前更新应用程序的所有代码)相比,这种模式能在短得多的时间内创造增量价值。它还提供了一种采用微服务的增量方法 — 如果您发现该方法不适合您的环境,只需在需要时改变发展方向即可。
当然,不能假设一种模式可应用于所有情形。要让此方法取得成功,必须具备一些前提条件:
- 基于 Web 或 API 的整体式应用程序: 这是第一个要求。Strangler 应用程序的唯一目的是,让您有一种能在新功能与旧功能之间轻松来回切换的方法。如果使用 Web 应用程序,该应用程序的 URL 结构会提供一个选择以何种方式实现系统的哪些部分的框架。另一方面,瘦客户端应用程序或类似的原生移动应用程序不太适合此方法,因为它们不一定有允许您以相同方式拆分应用程序的结构。
- 标准化的 URL 结构(URL 的真正用途): 尽管 Web 应用程序都将根据 Web 结构所规定的一些标准(比如使用 HTTP 和 HTML)来运行,但您可以使用许多不同的应用程序架构来实现这些 Web 应用程序。不过,此方法中仍有许多自由发展空间。例如,当服务请求下方有一个中间层时(像门户方法一样),如果您使用 URL 来拆分应用程序,可能会遇到问题;切换和路由的决策不是在浏览器级别上制定的,而是在应用程序中更深入的地方制定的,后者更加复杂。
- 元 UI: 当 UI 是“元” UI 时(比如当它基于业务流程和/或是动态构造的时候),该方法仍然有效,但分块更大且必须一次性全部实现。这是因为您必须重新创建整个生成框架,或者在最低限度上重新创建所有与当前非基于微服务的业务模型交互的功能。
就像适用该模式的情况一样,它也有 不 适用的情况 — 或者至少无法轻松应用。这些情况包括:
- 不是一次一个页面地应用它: 最小的拆分单元 (sliver) 是一个微服务。您想要避免同时拥有数据的两种不同访问方法,以避免一致性问题。
- 不一次性完全应用它: 如果能够一次性应用于整个应用程序,也就不必应用 Strangler 模式,不是吗?
您需要交叉考虑应用程序重构的两个不同方面:将后端重构为微服务设计(内部部分),重构前端以适应微服务以及创建任何会推动重构的新功能更改(外部部分)。
- 识别应用程序设计中的有界上下文 — 在图书 领域驱动设计_中,Eric Evans 对有界上下文的陈述是“定义一个模型所适用的上下文”。有界上下文是一个共享概念框架,它将一些实体的含义限制在一个更大的业务模型集合中。在航空应用程序中,航班预定是一个有界上下文,而航空公司的客户忠诚度计划是一个不同的有界上下文。尽管它们可能共享一些术语(比如 “航班”),但使用和定义这些术语的方式可能截然不同。
- 选择最小且重构成本最少的有界上下文 — 按复杂性从低到高对其他有界上下文进行排序。您可能希望从最简单的有界上下文开始,以便在执行更复杂(且成本可能更高)的重构任务之前证明重构的价值(并解决采用该流程的任何问题)。
- 在上下文内从概念上规划微服务 — 通过应用来自 [Evans] 的实体、聚合和服务模式,规划微服务的大致 URL 结构和整体责任。请注意,此刻,我们不打算实际对所有这些微服务进行详细设计!我们只想尝试了解可能存在哪些微服务,以便能够在接下来的一组步骤中使用该“猜测”。
由于事实上您不仅会更改后端实现来包含微服务,通常还会在项目执行过程中执行大量前端 UI 更改,所以规划 Strangler 应用程序模式在棕地项目中的应用的过程通常更复杂。事实上,通常是前端更改(例如将站点实现为单页应用程序或移动应用程序)首先激发了实现微服务的渴望。对于微服务架构,不能假设您提前知道 UI 设计的准确结果,或者 UI 团队将进行哪些更改。但是您 可以 做出一些有助于您开始设计的简单假设:
- 分析现有 UI 中的屏幕之间的关系 — 这实际上意味着,您需要将一些屏幕分组到一组逻辑 流 中。一个流是一个简单概念 — 它是一组屏幕,这些屏幕相互连接来执行一项用户任务,比如在旅行网站上预定航班或在零售网站中结算购物车。这里需要注意的是,您的 UI 中只有有限数量的流,而且每个流对应于代表所处理的概念的一小组微服务。
- 向模型操作的相关方面应用最小惊讶原则 — 最小惊讶原则是软件工程和用户界面设计中的一条古老规则。它规定 系统应以大部分人认为它应采取的方式运行。 尝试一些适合此原则的简单假设;例如,如果拥有查询特定领域方面的流,您可以假设可能这个领域方面也应更新,即使您没有该方面的流。
- 调整分块大小 — 下面将更深入地讨论分块的概念,但就现在而言,可以假设它是一组相关的作品 (epic)。这里要考虑的问题是, 用户在一个流中工作是否合理,或者流之间的联系是否紧密,以至于一组流是用户可采用的最小的合理元素? 例如,客户资料管理与零售网站的剩余部分分开可能是合理的,因为它与网站的剩余部分的联系并不紧密。但是,将支付方式选择与结算流程的剩余部分分开,为支付提供一个与结算流程的剩余部分完全不同的 UI,这是不合理的。这违背了最小惊讶原则,所以应用该原则会导致您将这两部分保持在一个逻辑单元中。
- 选择一次发布整个分块,还是将每个分块当作一系列拆分单元 — 下一节将介绍此方面的内容。
在 IBM Cloud Garage Method 中,我们使用来自敏捷方法的一些概念来帮助组织我们的工作。例如,一个 Hill(或 MVP 定义)通过初始流程被分解为 用户案例,用户案例表示 MVP 的各个可实现的元素。相关用户案例被分组到描述更高级的系统功能的 作品 中。
这将我们带回到了通过 Strangler 应用程序模式逐步取代系统的挑战。作品按 分块 分组,分块通过实现限制或变成初始大规模转出单元的用户体验关系而结合在一起。在大部分情况中,一个分块由一个定义了用户任务的 UI 流捆绑,该流中的所有部分都是以一致方式实现的。
小队 (Squad) 实现作品:一个小队可在一个分块中实现一个或多个作品,但一个小队的最小实现责任元素是一个作品。小队将定义该作品的用户案例添加到一个包含要实现的用户案例的 具有现有顺序的工作清单 中。
但是,在尝试从一组发起者用户接收中间反馈时,一个分块仍是一个很大的转出单元。因此,我们定义一组可在内部使用的更小的发布元素来获取该反馈。 拆分单元 是最小的可发布单元,其中包含一个微服务和使微服务适合最终用户而执行的相关更改。所以尽管一个分块可能是预定汽车票或飞机票的整个流程和实现该流程所需的所有微服务,但拆分单元可能是该流程中代表一个步骤(比如显示订票确认信息以及获取该确认所需的微服务)的一页。所以分块可能由拆分单元组成,拆分单元不断发布且以受限制的方式公开来获取反馈,但仅在分块所表示的整个任务可行时才发布给最终用户。
在本文中,我介绍了 Strangler 应用程序模式的几个方面 — 它何时适用,何时不适用,以及它对版本管理有何意义。我还介绍了我们在 IBM Cloud Garage 中的咨询实践中使用的两个新术语,希望它们对您有所帮助。具体地讲,我重点介绍了在应用 Strangler 应用程序时规划微服务开发的过程,以及管理应用程序中的功能发布的过程。
本文翻译自: Apply the Strangler Application pattern to microservices applications(2017-01-13)