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

385次阅读  |  发布于2年以前

你的团队决定是时候摆脱那个旧的、笨重的单体了,它运行得很好,但是单体已经变得如此之大,以至于你花费更多的精力来维护它而不是添加功能。这里有 12 个技巧,可帮助您尽可能顺利地过渡到微服务。

#1 确保你知道你在做什么

重写从来都不是一件容易的事,但是从单体应用到微服务,你改变的不仅仅是编码方式;你正在改变公司的运营模式。你不仅需要学习一个新的、更复杂的技术栈,管理层还需要调整工作文化,将人员重组为更小的跨职能团队。

如何最好地重组团队和公司是值得单独发帖的主题。在本文中,我想重点介绍迁移的技术方面。 首先,在开始之前尽可能多地研究采用微服务所涉及的权衡是很重要的。您希望绝对确定微服务(而不是其他替代解决方案,例如模块化单体)是适合您的解决方案。

首先学习有关微服务架构的所有知识,并查看一些示例项目以了解其工作原理。这里有些例子

#2 制定计划

拆除单体应用需要大量准备工作,因为旧系统必须在过渡期间保持运行。

迁移步骤可以通过工单进行跟踪,并像任何其他任务一样在每个 sprint 中进行。这不仅有助于获得动力(实际上有朝一日实现迁移),而且让业务所有者了解团队如何计划实施如此大的变化。

在计划期间,您必须:

除非您从一个相当简单的单体架构迁移,否则您将需要高级技术,例如领域驱动设计 (DDD)。

#3 把所有东西都放在一个 monorepo 中

当你分解单体时,大量代码将从单体中移出并转移到新的微服务中。monorepo可帮助您跟踪这些类型的更改。此外,将所有东西放在一个地方可以帮助您更快地从故障中恢复。

您的单体应用很可能已经包含在一个存储库中。因此,只需为微服务创建新文件夹即可。

#4 使用共享 CI 管道

在开发过程中,您不仅会不断推出新的微服务,还会重新部署单体应用。这个过程越快、越轻松,你的进步就越快。设置持续集成和交付(CI/CD) 以自动测试和部署代码。

如果您使用 monorepo 进行开发,则必须牢记以下几点:

配置测试报告以快速发现和排除故障。

#5 确保你有足够的测试

当我们确定代码没有回归时,重构会更加令人满意和有效。自动化测试让您有信心持续发布单体更新。

一个很好的起点是测试金字塔。您将需要大量的单元测试、一些集成测试和一些验收测试。

旨在像在持续集成管道中一样经常在本地开发机器上运行测试。

#6 安装 API 网关或 HTTP 反向代理

随着微服务的部署,您必须隔离传入流量。迁移的功能由新服务提供,而尚未准备好的功能由单体提供。 有几种路由请求的方法,具体取决于它们的性质:

使用 API 网关和 HTTP 反向代理将请求路由到适当的端点。您可以在非常细粒度的级别上在单体和微服务之间切换。 迁移完成后,网关和代理将保留——它们是任何微服务应用程序的标准组件,因为它们提供转发和负载平衡。如果服务出现故障,它们还可以充当断路器。

#7 考虑一体成型的模式

好的,这仅适用于您计划将容器或 Kubernetes 用于微服务的情况。在这种情况下,容器化可以帮助您实现基础架构的同质化。一体式整体模式包括在 Docker 等容器内运行整体。 如果您以前从未使用过容器,那么这是熟悉该技术的好机会。这样一来,您就离了解 Kubernetes 更近了一步。要学习的东西很多,所以要为陡峭的学习曲线做好计划:

容器化单体应用是标准化部署的一种方式,也是学习 Kubernetes 的绝佳第一步。

#8 热身于变化

习惯微服务需要时间,所以最好从小处着手,为新范式做好准备。留出足够的时间让每个人都进入正确的心态、提高技能并从错误中吸取教训,而不会受到最后期限的压力。 在这些初步的初步步骤中,您将学到很多关于分布式计算的知识。您必须处理云 SLA,为您自己的服务设置 SLA,实施监控和警报,定义跨团队通信的渠道,并决定部署策略。 选择一些容易开始的东西,比如与单体架构的其余部分几乎没有重叠的边缘服务。例如,您可以先构建身份验证微服务并路由登录请求。

选择一些容易开始的东西,比如简单的边缘服务。

#9 使用功能标志

功能标志是一种无需重新部署即可更改系统功能的软件技术。您可以使用功能标志在迁移时打开和关闭部分单体应用、试验替代配置或运行 A/B 测试。 启用功能标志的迁移的典型工作流程是:

因为功能标志允许我们将非活动代码部署到生产环境并随时切换它,所以我们可以将功能发布与实际部署分离。这为开发人员提供了极大的灵活性和控制力。

#10 模块化单体

如果你的单体应用是一堆代码,那么一旦迁移完成,你很可能会得到一堆分布式代码。就像在全面翻新之前收拾房子一样,模块化整体结构是必要的准备步骤。 模块化单体是一种软件开发模式,由独立且可互换的垂直堆叠模块组成。与模块化单体相反的是经典的 N 层或分层单体。

分层的单体很难解开——代码往往有太多的依赖关系(有时是循环的),使得更改难以实现。 模块化单体是微服务的下一个最佳选择,也是迈向微服务的垫脚石。规则是模块只能通过公共 API 进行通信,默认情况下一切都是私有的。因此,代码的交织更少,关系易于识别,依赖关系清晰。

有两种模式可以帮助你重构单体:Strangler Fig 和 Anticorruption Layer。

Strangler Fig

在Strangler Fig模式中,我们将整体重构从边缘到中心。我们在边缘咀嚼,逐步重写孤立的功能,直到整体重做。 模块之间的调用通过“扼杀外观”进行路由,该外观模拟和解释遗留代码的输入和输出。一点一点地,模块被创建并慢慢取代旧的单体。

单体是一次模块化的。最终,旧的巨石消失了,取而代之的是新的。

反腐败层模式 您会发现,在某些情况下,当您重构整体时,一个模块中的更改会传播到其他模块。为了解决这个问题,您可以在快速变化的模块之间创建一个转换层。此防腐败层可防止一个模块中的更改影响其余模块。

反腐败层通过转换模块和单体之间的调用来防止更改传播。

#11 解耦数据

超级强大的微服务使您能够随时部署任何微服务,而与其他微服务几乎没有协调。这就是为什么必须不惜一切代价避免数据耦合的原因,因为它会在服务之间产生依赖关系。每个微服务都必须有一个私有且独立的数据库。 意识到您必须将单体应用的共享数据库非规范化为(通常是冗余的)较小的数据库,这可能会令人震惊。但数据局部性最终将让微服务自主工作。

上图是将数据解耦到独立的数据库中。 解耦后,您必须安装机制以在转换过程中保持新旧数据同步。例如,您可以设置数据镜像服务或更改代码,以便将事务写入两组数据库。

在开发过程中使用数据复制来保持表同步。

#12 添加可观察性

新系统必须比旧系统更快、性能更高、可扩展性更强。否则,为什么要用微服务呢? 您需要一个基线来比较旧的和新的。在开始迁移之前,请确保您有良好的指标和日志可用。安装一些集中式日志记录和监控服务可能是一个好主意,因为它是任何微服务应用程序可观察性的关键组件。

结论

微服务之旅绝非易事。但我希望通过这些提示,您可以节省一些时间和挫败感。 请记住以小增量进行迭代,利用 CI/CD 来保证单体应用程序正在接受回归测试,并将所有内容保存在一个存储库中,以便在出现问题时随时回退。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8