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

如何在实践中将单体架构迁移到微服务

时间:2023-03-14 18:18:44 科技观察

如何在实践中将单体架构迁移到微服务优点和缺点非常简单。但要了解其他东西——战略。建造单体是因为它们更容易上手。当系统已经投入生产时,微服务通常是出于需要而出现的。然而,在决定何时迁移时会出现许多问题——例如,如何确定服务的边界?如何验证微服务架构的自愈特性?这对于服务网格的分布式方面尤其具有挑战性。应用程序需要被视为它的一部分才能被中断。本文的目标是保持您在传统单体应用程序中的便利性,同时避免与领域相关的紧耦合。本文概述了您在执行此迁移时可以使用的一些实用方法。决定整体应该是一个模块化的整体,这样它就可以很容易地被分解。将整体称为“互连的代码块”是一种误解,但事实远非如此。大多数单体应用程序使用包和模块等现代编程语言的特性来分隔各个部分。模块化单体的各个部分之间的调用是通过定义明确的接口或事件总线进行的。支持单体应用程序的立场可能源于Java背景,因为Java特别适合大型单体应用程序。根据其架构、语言、问题域等,拆分代码库的点将完全不同。如何在这方面做出客观的选择?何时是开始迁移到微服务的最佳时机?微服务架构迁移最重要的前提是授权分离。如果不将其作为外部服务解耦,可能就没有前进的方向。这是微服务迁移中最难的部分。这样做的好处是可以在保持单体架构的同时采取这一步。如果您不能执行此迁移,则没有任何前进的意义。一旦完成,就会涉及其他几个因素:团队规模——随着团队的成长,保持凝聚力可能是一个挑战。这是可以通过回顾团队的成长来轻松对标的部分。密切关注入职速度和其他指标,例如解决问题的时间。这些可能是项目复杂性的最佳指标。相互依赖——如果项目高度相互依赖并且没有明确的分界线,微服务的好处可能会成为障碍。有些项目本质上是深度混合的,各个部分之间没有明确的区分。注意不同模块之间的事务完整性。微服务之间不能进行事务管理等功能。如果您有一个必须可靠且一致的系统,例如需要始终保持一致的银行系统,则交易的边界必须位于单个服务内。这些类型的事情会使迁移过程特别困难。测试——如果没有大量特定于模块的测试和大量集成测试,您将无法执行此类操作。与任何其他方法相比,审查测试代码将使您更深入地了解准备情况。那么,隔离测试模块在逻辑上是否可行?了解这些后,您就可以开始估算从单体应用程序迁移到微服务可能带来的好处。从哪儿开始?假设单体代码已经相对模块化并且支持单点登录(SSO),您可以选择任何您想要的模块。那么,您怎么知道哪一个会在投入大量时间和精力后获得最好的回报呢?理想情况下,用户希望瞄准带来最大好处和最容易迁移的部分:检查问题跟踪器/版本控制——哪个模块最有可能被破坏?检查模块化——哪个模块最小且相互依赖最少?数据能分离的干净吗?最好从容易实现的目标开始。分析应用程序——哪个模块最昂贵并且可以从扩展中获益?这些事情在本地运行时非常简单,但应用程序在生产环境中的行为通常与其本地或临时环境非常不同。在这些情况下,可以使用运行时行计数器等开发人员可观察性工具来评估使用情况。在选择模块进行突破时,需要在收益和实用性之间取得平衡。避免使用TinyMonoliths微服务用户将继续构建不遵循通常规则的产品。“自愈”是最明显的例子。将单体应用程序解耦为微服务应用程序非常困难。有必要隔离各个部分,并确保一切都在规模上合理运作。或者更糟的是,在停机期间。当可部署服务出现故障时,系统如何生存?如何测试这样的产品?这种架构的最大问题之一是部署规模。将单个服务打包到发现系统和带有断路器的API网关中,以启用修复属性。API网关和类似服务通常是基于SaaS的解决方案,但即使用户自己部署它们,也很难在生产中准确复制。典型的复杂性包括将URL编码到网关和实际代码中。不小心绕过网关,直接访问服务器或底层基础设施。这些是在遗留代码和大型系统中难以检测到的微妙事物。由于这种复杂的拓扑结构,在本地工作时几乎不可能正确测试修复行为。获得的任何结果都是不准确的,因为部署工作差异很大。但是你不能仅仅为了证明一点而关闭生产微服务。这是微服务架构的一大好处。在发现代码中,可以添加一个特例来为特定用户提供“虚拟”或失败的微服务。问题是这些症状可能难以验证,因为“自我修复”服务似乎正在运行。在这种情况下,可以通过日志或快照来验证代码是否正确以及模块是否确实已断开连接。例如,大多数API网关都可以用来模拟API不可用。然后,您可以通过调用并验证断路器是否已触发并且其结果仍然到达来检查其他服务是否按预期工作。系统似乎已经自我修复。但也许某些用户代码直接调用web服务并有效地绕过了API网关?我如何验证缓存中的所有内容是否正常工作,并具有预期的回退?这就是日志和快照的用武之地。这些可以添加到后端API以及断开连接的服务,以验证结果结果确实来自网关缓存。冲洗-重复当第一个微服务与单体应用程序分离时,这个过程最具挑战性。打破多余的碎片时,通常会变得更容易,直到单体消失。但在此过程中也存在挑战。最初,选择一个更容易实现的目标。随着我们的前进,出现了更多困难的挑战,需要为可能不太理想的服务划定界限。问题是这些步骤通常需要凭直觉来执行。但是在创建模块时,可能已经使用了逻辑分离而不是相互依赖。因此,两个模块可能有很深的依赖关系,作为微服务可能没有意义。将它们拆分到不同的位置,甚至将它们捆绑在一起可能更有意义。例如,可能有一个管理多个帐户的会计系统。逻辑分离可能会将在账户之间转移资金的代码移到一个单独的模块中,但这会使事情变得非常困难。在会计系统中,钱必须从一个账户到达并转移到另一个账户;它永远不会“消失”。当钱被添加到一个账户时,这些资金必须从另一个账户中减去,并且两者都需要在一次交易中发生。一个简单的解决方法可能是在一个请求中同时进行扣除和资金转移。但是,这并不能解决一般问题,因为资金可以从一个账户中提取并拆分到多个账户中。在多个小操作中执行此操作可能会导致副作用。这行得通,在这种情况下,将核心会计逻辑保留在账户系统中。其中一些相互依赖关系可以从代码中推断出来并重构为消息传递和异步调用。使用消息服务是最有效的解耦方式之一,很多语言和平台都支持各个部分之间的模块壁垒。这将整个模块与应用程序的其余部分隔离开来,并将交互限制在一个狭窄的界面中。通过设置此类障碍,可以使用编译器和IDE来强制执行模块限制。结论分解单体应用程序总是具有挑战性,将业务逻辑隔离到正确的域中需要时间和精力。特定于服务的通信开销和功能分区是在这种过程中产生影响的组成部分。没有交付保证,测试就更加困难。由于API网关、代理设置、发现等原因,生产环境与开发环境完全不同。遗留代码的成功迁移对客户来说是无缝的,它完全改变了动态。交付是不同的,验证部署是否成功比单体应用程序更具挑战性。当一切正常时,用户体验是相似的,但你如何验证呢?这就是工具的用武之地;可以使用开发人员可观察性工具(日志、计数器、日志)对其进行验证。即使生产失败,跨服务边界的修复仍然有效。但这绝非易事,因为松耦合只是第一步。不同形式的失败期间的行为只能在生产中进行测试,人们不希望生产失败只是为了证明他们的观点是正确的。原标题:MigratingMonolithstoMicroservicesinPractice,作者:ShaiAlmog