当前位置: 首页 > 科技观察

从单体应用迁移到微服务的十二种方法

时间:2023-03-20 14:46:36 科技观察

您的团队决定是时候摆脱旧的、笨重的、运行良好的单体应用了,但是单体应用已经变得如此庞大,以至于您需要花费更多的精力来维护它而不是添加功能。这里有12个技巧,可帮助您尽可能顺利地过渡到微服务。1.确保你知道自己在做什么重写从来都不是一件容易的事,但是从单体应用到微服务,你不仅仅是在改变编码方式;您正在改变公司的运营方式。不仅需要学习新的、更复杂的技术栈,管理层还需要调整工作文化,将人员重组为更小的跨职能团队。如何最好地重组团队和公司是一个值得单独发表的话题。在本文中,我想重点介绍迁移的技术方面。首先,重要的是在开始之前尽可能多地研究采用微服务所涉及的权衡。您希望绝对确定微服务(而不是其他替代解决方案,例如模块化单体)是适合您的解决方案。首先了解微服务架构,并查看一些示例项目以了解其工作原理。下面是一些示例2.制定拆除单体应用程序的计划需要大量的准备工作,因为旧系统必须在过渡期间继续运行。可以通过票证跟踪迁移步骤,并像执行任何其他任务一样执行每个冲刺。这不仅有助于获得动力(并在某一天实际迁移),而且让企业主了解团队计划如何实施如此大的变革。在规划期间,您必须:理清单体中的依赖关系。确定所需的微服务。为微服务设计数据模型。开发一种在单体数据库和微服务数据库之间迁移和同步数据的方法。设计API并计划向后兼容。捕获单体应用程序的基线性能。为新系统的可用性和性能设定目标。除非您是从相当简单的单体架构迁移,否则您将需要领域驱动设计(DDD)等高级技术。3.把所有东西都放在一个monorepo中当你分解monorepo时,很多代码会被移出monorepo并转移到新的微服务中。monorepo可帮助您跟踪这些类型的更改。此外,将所有内容集中在一个地方可以帮助您更快地从故障中恢复。很可能您的单体应用已经包含在存储库中。因此,只需为微服务创建新文件夹即可。4.使用共享的CI管道在开发过程中,您不仅要不断推出新的微服务,还要重新部署单体应用程序。这个过程越快越容易,你的进步就会越快。设置持续集成和交付(CI/CD)以自动测试和部署代码。如果您使用monorepo进行开发,则必须牢记以下几点:通过启用基于更改的执行或使用单一存储库感知构建工具(例如Bazel或Pants)来保持管道快速。通过仅对更新的代码运行更改,这将使您的管道更高效。配置多个促销,每个微服务一个,一个整体。使用这些促销活动进行持续部署。配置测试报告,方便快速排查故障。5.确保你有足够的测试当我们确定代码中没有回归时,重构会更加令人满意和有效。自动化测试让您有信心持续发布单体应用的更新。一个好的起点是测试金字塔。您将需要大量的单元测试、一些集成测试和一些验收测试。旨在像在持续集成管道中一样频繁地在本地开发机器上运行测试。6.安装API网关或HTTP反向代理随着微服务的部署,您必须隔离传入流量。迁移的功能由新服务提供,而尚未准备好的功能由单体提供。根据请求的性质,有多种路由请求的方法:API网关允许您根据经过身份验证的用户、cookie、功能标志或URI模式等条件转发API调用。HTTP反向代理执行相同的操作,但用于HTTP请求。在大多数情况下,单体实现了UI,因此大部分流量都流向那里,至少在最初是这样。使用API网关和HTTP反向代理将请求路由到适当的端点。您可以在非常细粒度的级别上在单体和微服务之间切换。迁移完成后网关和代理将保留——它们是任何微服务应用程序的标准组件,因为它们提供转发和负载平衡。如果服务失败,它们还充当断路器。7.考虑单体模式好吧,这只适用于你计划使用容器或Kubernetes来实现微服务的情况。在这种情况下,容器化可以帮助您使基础设施同质化。Monolithic单体模式包括在Docker等容器中运行单体。如果您以前从未使用过容器,那么这是一个让您自己熟悉该技术的好机会。这样,你离理解Kubernetes又近了一步。有很多东西要学,所以计划一个陡峭的学习曲线:了解Docker和容器。在容器中运行单体应用程序。在容器中开发和运行您的微服务。完成迁移并掌握容器后,请了解Kubernetes。随着工作的进展,您可以扩展微服务并逐渐将流量转移给它们。容器化单体是标准化部署的一种方式,也是学习Kubernetes的重要第一步。8.热身以改变习惯微服务需要时间,因此最好从小处着手,为新范式做好准备。允许每个人有足够的时间进入正确的心态,提高他们的技能,并在没有最后期限压力的情况下从错误中吸取教训。在这些最初的初步步骤中,您将学到很多关于分布式计算的知识。您必须处理云SLA,为您自己的服务设置SLA,实施监控和警报,定义跨团队沟通的渠道,并决定部署策略。选择一些容易开始的东西,比如与单体应用的其余部分几乎没有重叠的边缘服务。例如,您可以先构建一个身份验证微服务并路由登录请求。选择一些容易上手的东西,比如简单的边缘服务。9.使用功能标志功能标志是一种无需重新部署即可更改系统功能的软件技术。您可以使用功能标志在迁移时打开和关闭单体应用的某些部分,试验替代配置或运行A/B测试。启用功能标志的迁移的典型工作流是确定要迁移到微服务的整体功能的一部分。用函数标志包装函数。重新部署单体。构建和部署微服务。测试微服务。一旦满意,通过关闭它来禁用单体上的功能。重复直到迁移完成。因为功能标志允许我们将非活动代码部署到生产中并随时切换它,所以我们可以将功能发布与实际部署分离。这为开发人员提供了极大的灵活性和控制力。10.模块化单体如果你的单体应用是一堆代码,那么一旦迁移完成,你很可能会得到一堆分布式代码。就像在全面翻新之前组装房屋一样,模块化整体结构是必要的准备步骤。模块化单体是一种软件开发模型,由独立且可互换的垂直堆叠模块组成。模块化单体的对立面是经典的N层或分层单体。分层单体很难解开-代码通常有太多(有时是循环的)依赖关系,使得更改难以实施。模块化单体是仅次于微服务的最佳选择,也是迈向微服务的垫脚石。规则是模块只能通过公共API进行通信,默认情况下一切都是私有的。因此,代码交织较少,关系很容易识别,依赖关系也很清楚。有两种模式可以帮助您重构单体应用:StranglerFig和AnticorruptionLayer。StranglerFig在StranglerFig模式下,我们从边缘到中心重组整体。我们细嚼慢咽,逐步重写孤立的功能,直到整个事情都被重新设计。模块之间的调用通过模拟和解释遗留代码的输入和输出的“stranglefacade”进行路由。渐渐地,模块被创建并慢慢取代旧的单体。Monoliths一次是模块化的。最终,旧的巨石消失了,新的巨石取而代之。Anti-CorruptionLayerPattern您会发现,在某些情况下,当您重构单体时,一个模块中的更改会传播到其他模块。为了解决这个问题,您可以在快速变化的模块之间创建一个转换层。该反腐败层可防止一个模块中的更改影响其余模块。反腐败层通过转换模块和单体之间的调用来防止变更传播。11.解耦数据超级强大的微服务使您可以随时部署任何微服务,而无需与其他微服务进行协调。这就是为什么必须不惜一切代价避免数据耦合的原因,因为它会在服务之间创建依赖关系。每个微服务都必须有一个私有且独立的数据库。意识到您必须将单体应用程序的共享数据库非规范化为一个(通常是冗余的)较小的数据库可能会令人震惊。但数据局部性最终将允许微服务自主工作。上图是将数据解耦成一个独立的数据库。一旦分离,您必须安装机制以在转换期间保持新旧数据同步。例如,您可以设置数据镜像服务或更改代码,以便将事务写入两组数据库。在开发过程中使用数据复制来保持表同步。12.添加可观察性新系统必须比旧系统更快、更高效、更具可扩展性。否则,为什么要费心微服务呢?您需要一个基线来比较旧的和新的。在开始迁移之前,请确保您有可用的良好指标和日志。安装一些集中式日志记录和监控服务可能是个好主意,因为它是任何微服务应用程序可观察性的关键组件。结论微服务之旅绝非易事。但我希望通过这些提示,您可以节省一些时间和挫折感。请记住以小增量进行迭代,利用CI/CD来确保单体正在接受回归测试,并将所有内容保存在一个存储库中,以便您可以在出现问题时随时回滚。Banq注:本文以小增量谨慎谨慎的方式对原有系统进行了重构,但没有充分认识到单体和微服务是两种完全不同的架构风格,这是战略方向的差异。为什么?因为微服务比单片分割小,多小?它是基于DDD的有界上下文进行切分的,需要从战略背景和大景观的角度来考虑上下文。因此,是团队对业务理解的认知有了很大的提升和改变。这种突如其来的欢快结果,往往是南北方向差异较大,摸着石头过河的小增量改造,只适用于方向未确定或方向大概率不偏的情况下.这种重构听起来很有道理,但完全不切实际。从单体到微服务的迁移,不仅仅是技术上的改变,更是业务知识的提升,更有可能是团队彻底改变。新团队能否容忍在旧思维、旧单体下妥协?