向微服务迁移:迁移和架构异味

摘要

向微服务迁移是一个容易出错且存在严重陷阱的过程,错误会导致高昂的成本。微服务是一种相对较新的架构风格,导致目前缺乏将单体应用迁移到微服务的通用指南。我们提出了9种常见的陷阱,以坏味道的形式呈现,并提供了相应的潜在解决方案。通过使用这些坏味道,可以在迁移过程中识别并纠正这些陷阱。

1 引言

微服务是一种架构风格,用于开发通过轻量级机制进行通信的、可独立且自动部署的服务[23]。“微服务”这一术语如今已成为流行语。尽管关于微服务本身是否是一种架构风格,或仅仅是一种实现面向服务的架构(SOA)的方式仍存在争议,但其在实际应用中具有明确的区别[61]。

不存在适用于所有情况的微服务策略,即每个解决方案都有其不同的策略。这种繁多的策略使得概括其特征变得困难。然而,微服务之间存在一些共同特征,例如通过服务进行组件化、智能端点与 dumb pipes(哑管道)以及去中心化 [23]。

近年来,微服务架构风格因其潜在优势而变得越来越流行,这些优势包括技术异构性、弹性、可扩展性、简化部署、生产力、可重用性以及可替换性等[51]。此外,一些研究报道称,在迁移到微服务架构后,复杂性降低、耦合度更低、内聚性更高、集成更简单、可重用性更好,并实现了性能提升[9, 27]。

然而,采用微服务架构的优势也伴随着分布式系统的复杂性,例如需要考虑弹性、扩展性和数据一致性[43]。近年来出现了许多新技术来应对这些复杂性,例如容器化、自动化部署和应用扩展;这些技术被认为是推动微服务发展的使能因素。此外,快速资源供应、基本监控和快速应用部署是任何微服务应用的前提条件[21]。此类需求在云环境中天然具备,因此云成为微服务的默认归宿。

尽管微服务存在固有的复杂性,但将单体应用迁移到微服务架构的迁移趋势已变得明显。多个开发团队已经发布了他们迁移到微服务架构的经验,其中包括一些成功案例。然而,由于微服务的特性,遵循这些经验建议可能并不适用于所有策略。因此,应收集在这一迁移趋势中公开可用的知识,例如最佳实践、成功案例和陷阱。随后将这些知识以迁移和架构异味的形式进行整合,可为计划将其应用迁移到微服务的开发团队提供有用的信息。

本文中,我们通过梳理学术界和灰色文献中的58种不同资料,提出了5种新的架构坏味和4种新的迁移坏味。本文其余部分结构如下:第2节概述相关工作;第3节提出研究问题;第4节说明我们的方法论;第5节介绍5种新的架构坏味,而4种新的迁移坏味在第6节中介绍;第7节讨论有效性威胁;第8节总结全文。

2 相关工作

重构是软件工程知识体系(SWEBOK)的一部分。最初,重构旨在重构代码。然而,Stal 将重构的概念扩展到包括软件架构重构[53]。在对架构进行重构时,会以整体方式更改软件以解决架构异味。

微服务架构是一种新的架构风格,用于开发可独立且自动部署的服务化应用程序[23]。因此,希望采用这种新架构的开发团队必须迁移其现有系统。为了研究向微服务的迁移过程,泰比等人调查了21位已采用微服务架构的实践者[56]。该调查旨在确定迁移的原因以及迁移过程中出现的问题。报告中的迁移原因主要由技术动机驱动,例如降低维护成本和提升可扩展性。而主要问题包括:由于架构风格本身具有复杂性,需要有经验的开发者;采用微服务所需投入带来的经济负担;以及资深开发者和架构师对新技术的抵触情绪。这表明专家们需要迁移模式来辅助向微服务的迁移。随后,泰比等人开展了一项系统映射研究,以收集微服务的相关原则和模式目录[57]。然而,他们的重点在于收集用于构建目录的架构模式,而非识别向微服务迁移时可能遇到的陷阱。

为了帮助实践者识别潜在的陷阱,塔比和莱纳杜齐定义了与微服务架构相关的11种坏味道[55]。这些坏味道是通过分析72名实践者经历的265种不良实践而识别出来的。然而,他们的研究仅基于实践者的经验,未包含最先进技术方面的建议。Garousi等人指出,在进行软件工程领域的研究时,有必要同时纳入最先进技术与实践来源。如果仅专注于研究贡献,则会遗漏已有的知识体系[25]。因此,有必要开展一项涵盖学术和灰色文献的最佳实践文献调查,以识别更多潜在的陷阱及其解决方案。在本研究中,我们进行了这样的文献调查。

3 研究问题

RQ1)微服务中存在哪些架构和迁移坏味?

  • 动机 :识别微服务架构和迁移过程中的坏味道,有助于个人在拆分单体应用时做出更好的决策,从而支持其重构工作。
  • 方法 :收集学术界和灰色文献中的出版物,了解其在重构过程中总结的经验教训 - 将单体应用迁移到微服务,使我们能够提取并推断出常见的陷阱。此外,文献的纳入或排除取决于其对微服务架构和迁移实践的普遍合理性的贡献。最后,这些知识以架构坏味道和迁移坏味的形式进行汇总。

RQ2)如何避免微服务中的架构坏味道和迁移坏味?

  • 动机 :识别微服务架构和迁移中坏味道的潜在解决方案流程可以帮助个人避免或修复设计中的坏味道。
  • 方法 :从收集的出版物中,可以提取并推断出常见的最佳实践和陷阱解决方案。这些发现被作为RQ1中检测到的架构的和迁移坏味的潜在解决方案进行呈现。

4 实验设置

使用两个搜索引擎来收集资料,即谷歌学术和谷歌。谷歌学术允许通过搜索词查找学术文献,而谷歌搜索引擎则可用于在互联网上搜索灰色文献。所有与搜索相关的活动均在火狐浏览器的便携版本中进行,以确保通过其浏览历史记录实现研究结果的可追溯性。此外,所有找到的网络资源均被下载并以 HTML和PNG格式保存,同时在Bibtex数据库中创建相应条目。每个资源均用查找该资源所使用的搜索词以及文献类型进行标记。

在每个搜索引擎中,使用以下搜索词来查找相关文献: refactoring microservices 和 migrating microservices。在谷歌学术中,从2014年起按出版时间渐进式地调查这两个搜索词的结果,因为该术语于2014年由福勒和刘易斯在灰色文献中定义[23]。每项搜索结果均通过摘要进行审查,并根据其相关性进行筛选。接下来,在谷歌引擎中搜索灰色文献时,相关条目通常位于前几页结果中。因此,当结果不再包含经验教训或最佳实践时,我们即停止搜索。最后,我们的搜索于2018年4月结束,此后发表的任何文献均未被纳入考虑。

我们的检索共得到58个相关来源,其中学术文献来源34个 (58,62%),灰色文献来源24个(41,37%)。在检索“微服务重构”时,我们找到24个学术文献来源和16个灰色文献来源。此外,在检索“微服务迁移”时,我们找到10个学术文献来源和8个灰色文献来源。表1按检索词和来源总结了我们的发现。最后,下一部分中的坏味是从所有相关来源中推断得出的。

微服务重构 学术文献 灰色文献
24 16
微服务迁移 10 8
总计 34 24

5 架构异味

5.1 单层团队

描述 :康威定律指出,系统的设计结构反映了设计该系统的组织沟通结构 [15]。如果一个团队按层次划分,例如分为用户界面、应用逻辑和数据库团队,那么简单的变更可能需要在团队之间进行耗时且费力的审批。因此,团队可能会在其能够访问的任何层次引入逻辑。尽管这种问题并非微服务所独有,但其存在可能会在微服务中更为明显。每个服务都应该完全独立于其他服务,然而,团队可能会为了简化工作而将职责集中到一个较大的服务上,并使其他服务对其产生依赖。这违背了微服务的独立性原则,因此应避免这种情况。

解决方案 :按服务拆分跨职能团队。每个团队应包含服务完整开发所需的各项技能,以确保各团队及其服务的独立性。然而,开发团队之间的协调也不容忽视。

学术文献来源 :[1, 5, 9–11, 19, 36, 37, 43, 47]
灰色文献来源 :[2, 23, 26, 32, 35]

5.2 贪婪的服务容器

Description : DevOps实践与微服务的目标一致[5]。例如,持续交付能够实现软件系统的按需自动化部署。这种自动化被认为对微服务至关重要,尤其是在考虑高度可扩展的系统时。容器化减少了部署时间,因此被视为微服务架构风格的主要推动力之一。如果不使用这些技术,将会给应用程序的管理和编排带来全新的复杂性层次。然而,它们仍然需要花费时间进行设置。一个试图走捷径的团队可能会为整个应用程序定义一个容器,以简化设置过程。但这样做会使容器变得笨重,并削弱服务之间的独立性。

解决方案 :每个服务使用容器。这可以缩短部署时间,并实现资源分配的自动化。此外,每个服务使用一个容器有助于系统的可扩展性,因为它们可以轻松地自动复制。尽管存在其他方法,例如使用镜像的完全虚拟化,但这些方法通常创建速度较慢且耗时。因此,普遍共识是在微服务架构中使用容器。

学术文献来源 : [4–6, 8, 10–12, 18–20, 27, 28, 34, 36, 38, 43, 46,47,51, 56–58, 61]
灰色文献来源 : [7, 14, 16, 30–32, 35, 39, 41, 54]

5.3 单一DevOps工具链

Description : 微服务架构需要DevOps工具链,例如持续交付、持续集成、监控和编排。通常单体应用会被拆分为多个服务,每个服务都需要独立创建DevOps工具链。然而,在时间紧迫的情况下,团队可能会试图走捷径,为所有微服务定义相同的流水线。这将消除服务的自治性,并可能完全丧失该架构风格的大部分优势。

解决方案 :为每个微服务建立独立的自治流水线。这意味着每个服务都有完整的 DevOps 工具链,使其能够从其他服务中自主地进行扩展、监控、开发等操作。

学术文献来源 : [4–6, 8, 10, 11, 18, 19, 34, 36, 43, 47, 57, 58,61,62]
灰色文献来源 : [7, 13, 21, 35, 39, 45, 49]

5.4 忽视文档

描述 :记录任何应用程序通常都是一个好主意。然而,这项任务往往被忽视或根本没有维护,导致文档不一致且过时。这种问题在任何软件系统中都存在,但在微服务中,记录暴露的 API 尤为重要。随着独立服务数量的增加,很容易失去对系统的整体概览。此外,在多个团队协作实现微服务时,缺乏适当的文档可能会阻碍合作。

解决方案 :尽可能使用 API 代码内文档框架(如 Swagger)。否则,需确保每个团队负责维护其服务的已发布 API。

学术文献来源 :[4, 19, 20, 43]
灰色文献来源 :[7, 35, 52, 61]

5.5 磨削尘埃或粗糙的服务

Description : 单体应用必须被拆分为服务,为此必须确定适当的粒度。这取决于应用程序的实际功能,而错误的粒度可能会带来严重的副作用。如果粒度过粗,微服务的优势可能实际上并不明显;而如果粒度过细,则可能由于网络延迟或其他问题引发性能问题。

解决方案 :可以从单体应用中提取的服务可以通过领域驱动设计技术来确定,例如限界上下文 [43, 59]。限界上下文为定义服务粒度提供了一个良好的初始方法。然而,所产生的粒度可能并不适用于所有应用程序在其演进过程中的需求。因此,必须持续监控微服务,并在必要时将其合并或拆分,以提升系统的整体性能。

学术文献来源 :[27, 33, 40, 42, 43]
灰色文献来源 :[17, 22, 23, 29, 45]

6 迁移异味

6.1 认为微服务是灵丹妙药

Description : 尽管微服务看似前景广阔,但其优势伴随着许多固有的复杂性和挑战,可能会带来高昂的成本。因此,这种架构风格对许多应用程序来说可能并不值得。

解决方案 :采用微服务的潜在优势和风险必须进行彻底分析。此外,还应制定不使用微服务的替代方案。然后对所有可能的方案进行比较。在分析之后,如果微服务的优势明显,方可决定进行迁移。架构似乎仍然是最佳解决方案。然而,在迁移过程中可能会出现许多问题和陷阱。因此,必须谨慎规划迁移过程。否则,微服务带来的好处可能会被错误导致的意外成本所抵消。

学术文献来源 :[5, 6, 11, 20, 36, 43, 56]
灰色文献来源 :[30, 60]

6.2 一次性将所有服务重写为微服务

Description : 重写任何应用程序都不是一件简单的事,而且通常不是一个好主意。这样做可能会无意中引入许多新的故障,从而带来不必要的风险。因此,将单体应用迁移到微服务的最佳方法是渐进式地进行,即逐个服务地迁移。

解决方案 :必须使用领域驱动设计(DDD)中的技术来识别单体应用的服务,例如限界上下文模式 [43, 59]。通过限界上下文,大型系统可以根据领域进行模建,每个领域被视为一个微服务。这确保了功能的修改或添加被隔离在特定领域,即某个微服务中。此外,应避免在一个微服务中包含多个限界上下文。一旦识别出服务,就应逐步将其从单体应用中剥离并转化为微服务。迁移应从一个简单的服务开始,以便开发团队积累构建首个微服务的经验。即使提取出的服务较为简单,单体应用的复杂性也在一定程度上得到了降低。通过持续迭代地执行此过程,单体应用将逐步转变为微服务。

学术文献来源 :[5, 12, 43, 56]
灰色文献来源 :[2, 3, 22, 26, 39, 41, 45, 48, 50, 50]

6.3 边做边学

Description : 由于分布式系统本身具有复杂性,组建一支缺乏经验的开发者团队来开发分布式系统通常不是一个好主意。他们的经验不足可能导致更高的成本和更长的开发时间,因为他们需要应对分布式系统中的各种陷阱。这种问题并非微服务所独有,在任何软件开发中都可能出现。然而,微服务固有的学习曲线对缺乏经验的开发者来说可能过于陡峭,因为它要求开发者掌握开发过程中的许多不同方面的知识。

解决方案 :确保团队中至少有几位在分布式系统方面经验丰富的人。如果无法做到这一点,但又必须采用微服务策略,则可以从一个小团队开始,开发一个简单的微服务。一旦该团队积累了足够的经验,便将其拆分为新组建的团队,并加入其他开发人员。通过这种方式,部分开发人员已获得相关经验,能够领导新的团队。

学术文献来源 :[5, 6, 43, 57]
灰色文献来源 :[22, 49]

6.4 忽视CAP定理

描述 :Brewer的CAP定理指出,一个分布式数据存储无法同时提供以下三项保证中的两项以上:一致性、可用性和分区容忍性。由于微服务的特性,权衡的天平倾向于可用性和分区容忍性,即我们实现的是最终一致性。

解决方案 :尽管无法确保始终如一的一致性,但在微服务中意识到这一点并提前规划至关重要。例如,处理不一致的状态,并实施检测和纠正此类不一致的方法,是一种可能的解决方案。采用领域驱动设计实践或命令查询职责分离(CQRS)可以通过限制服务之间的共享数据来缓解数据不一致问题。然而,如果始终保证一致性非常重要,那么微服务架构可能并非合适的策略。

学术文献来源 : [8, 10, 11, 18, 24, 34, 36, 43, 57, 61]
灰色文献来源 : [23, 35, 44, 50]

7 效度威胁

7.1 结论有效性

为了在合理程度上确保我们结论的有效性,我们为每个已呈现的坏味道包含了所有导致这些结论的相关来源。此外,本研究纳入了学术和灰色文献,以确保适当的异质性。

7.2 内部有效性

我们的检索并非详尽无遗,相关研究来源可能已被排除,因为来源的纳入与排除是基于我们的判断和经验。然而,为了确保结果的可重复性,我们报告了所使用的搜索引擎及检索术语。

7.3 构念有效性

我们进行学术研究的总体经验不足,这对我们的研究有效性构成了威胁。然而,我们的研究问题和方法论已与该领域的资深研究人员进行了讨论,这使我们对研究的有效性具有合理的信心。

7.4 外部有效性

我们的研究仅限于58个来源。尽管已尝试收集足够数量的文献,但我们不能认为我们的发现已经涵盖了将单体应用迁移到微服务的所有最佳实践、成功案例和陷阱。然而,我们在合理范围内纳入了最先进技术与实践方面的文献。作为未来工作,应评估所提出的坏味道的实用性和可理解性,并重新评估我们的结论。

8 结论

我们简要概述了学术界和工业界将单体架构迁移到微服务的明显趋势。接下来,通过梳理来自学术界和灰色文献的58种不同资料,我们提出了5种新的架构坏味道和4种新的迁移坏味,扩展了塔比和莱纳杜齐提出的11种坏味道列表[55]。此外,针对这些资料中讨论的9种坏味道,我们分别提出了可能的解决方案。我们的贡献为成功将单体应用重构为微服务提供了可操作的信息基础。

更多推荐