Java架构:一文读懂微服务架构的重构策略

你很有可能正在处理大型复杂的单体应用程序,每天开发和部署应用程序的经历都很缓慢而且很痛苦。微服务看起来非常适合你的应用程序,但它也更像是一项遥不可及的必杀技。如何才能走上微服务架构的道路?下面将介绍一些策略,帮你摆脱单体地狱,而无须从头开始重写你的应用程序。

通过开发所谓的绞杀者应用程序(strangler application),可以逐步将单体架构转换为微服务架构。绞杀者应用程序的想法来自绞杀式藤蔓,这些藤蔓在雨林中生长,它们包围绕树木生成,甚至有时会杀死树木。绞杀者应用程序是一个由微服务组成的新应用程序,通过将新功能作为服务,并逐步从单体应用程序中提取服务来实现。随着时间的推移,当绞杀者应用程序实现越来越多的功能时,它会缩小并最终消灭单体应用程序。开发绞杀者应用程序的一个重要好处是,与宇宙大爆炸式的彻底重写不同,它可以立刻落地,更快为企业提供价值。

有三种主要策略可以实现对单体的“绞杀”,并逐步用微服务替换之:

1) 将新功能实现为服务。 2)隔隔表现层和后端。 3) 通过将功能提取到服务中来分解单体。

***种策略阻止了单体的发展。它通常是一种快速展示微服务价值的方法,有助于让迁移和重构的工作获得公司内部各个层面支持。另外两种策略打破了单体。在重构单体时,你有时可能会使用第二种策略,但你肯定会使用第三种策略,因为它能实现将功能从单体迁移到绞杀者应用程序中。

下面让我们来看一看这些策略。

1.将新功能实现为服务

“挖坑法则”(The Law of Holes)指出:如果你发现自己已经陷入了困境,就不要再给自己继续挖坑了。当你的单体应用变得无法管理时,这是一个很好的可供参考的建议。换句话说,如果你有一个庞大的、复杂的单体应用程序,请不要通过向单体添加代码来实现新功能。这将使你的单体变得更庞大,更难以管理。相反,你应该将新功能实现为服务。

这是开始将单体应用程序迁移到微服务架构的好方法。它降低了单体的生长速度,加速了新功能的开发(因为是在全新的代码库中进行开发),还能快速展示采用微服务架构的价值。

把新的服务与单体集成

图 1显示了将新功能实现为服务后的应用程序架构。除了新服务和单体外,该架构还包括另外两个将服务集成到应用程序中的元素:

■ API Gateway:将对新功能的请求路由到新服务,并将遗留请求路由到单体。

■ 集成胶水代码:将服务与单体结合。它使服务能够访问单体所拥有的数据,并能够调用单体实现的功能。

集成胶水的代码不是一个独立组件。相反,它由单体中的适配器和使用一个或多个进程间通信机制的服务组成。

何时把新功能实现为服务

理想情况下,你应该在绞杀者应用程序中而不是在单体中实现每个新功能。你将实现新功能作为新服务或作为现有服务的一部分。这样你就可以避免和单体代码库打交道。不幸的是,并非每个新功能都可以作为服务实现。

因为微服务架构的本质是一组围绕业务功能组织的松耦合服务。例如,某个功能可能太小而无法成为有意义的服务。例如,你可能只需要向现有类添加一些字段和方法。或者新功能可能与单体中的代码紧耦合。如果你尝试将此类功能实现为服务,则通常会发现,由于过多的进程间通信而导致性能下降。你可能还会遇到数据一致性的问题。如果新功能无法作为服务实现,则解决方案通常是首先在单体中实现新功能。之后,你可以将该功能以及其他相关功能提取到自己的服务中。

以服务的方式实现新功能,可以加速这些功能的开发。这是快速展示微服务架构价值的好方法。它还能够降低单体的增长速度。但最终,你需要使用另外两种策略来分解单体。你需要通过将单体中的功能提取到服务,从而将单体中的功能迁移到绞杀者应用程序。你也可以通过水平分割单体架构来提高开发速度。我们来看看如何做到这一点。

2.隔离表现层与后端

缩小单体应用程序的一个策略是将表现层与业务逻辑和数据访问层分开。典型的企业应用程序包含以下各层:

■ 表现逻辑层:它由处理 HTTP 请求的模块组成,并生成实现 Web UI 的 HTML 页面。在具有复杂用户界面的应用程序中,表现层通常包含大量代码。

■ 业务逻辑层:由实现业务规则的模块组成,这些模块在企业应用程序中可能很复杂。

■ 数据访问逻辑层:包含访问基础设施服务(如数据库和消息代理)的模块。 表现逻辑层与业务和数据访问逻辑层之间通常存在清晰的边界。业务层具有粗粒度 API,由一个或多个封装业务逻辑的门面(Facade)组成。这个 API 是一个自然的接缝,你可以沿着它将单体分成两个较小的应用程序,如图 2 所示。

一个应用程序包含表现层,另一个包含业务和数据访问逻辑层。分割后,表现逻辑应用程序对业务逻辑应用程序进行远程调用。

以这种方式拆分单体应用有两个主要好处。它使你能够彼此独立地开发、部署和扩展这两个应用程序。特别是,它允许表现层开发人员快速迭代用户界面并轻松执行A/B测试,而无须部署后端。这种方法的另一个好处是它公开了业务逻辑的一组远程API,可以被稍后开发的微服务调用。

但这种策略只是部分解决方案。很可能至少有一个或两个最终的应用程序仍然是一个难以管理的单体。你需要使用第三种策略将单体替换为服务。

3.提取业务能力到服务中

将新功能实现为服务,并从后端拆分出前端Web应用程序并不会让你抵达胜利的彼岸。你仍将最终在单体代码中进行大量开发。如果你希望显著改进应用程序的架构并提高开发速度,则需要通过逐步将业务功能从单体迁移到服务来拆分单体应用。当你使用此策略时,随着时间推移,服务实现的业务功能数量会增加,而单体会逐渐缩小。

你想要提取到服务中的功能是对单体应用自上而下的一个“垂直切片”。该切片包含以下内容:

■ 实现API端点的入站适配器。

■ 领域逻辑。

■ 出站适配器,例如数据库访问逻辑。

■ 单体的数据库模式。

如图 3 所示,此代码从单体中提取并移至独立服务中。API Gateway 将调用提取的业务功能的请求路由到该服务,并将其他请求路由到单体。单体和服务通过集成胶水代码进行协作。集成胶水由服务中的适配器和使用一个或多个进程间通信机制的单体组成。

提取服务具有挑战性。你需要确定如何将单体的领域模型分成两个独立的领域模型,其中一个模型成为服务的领域模型。你需要打破对象引用等依赖。你甚至可能需要拆分类,以将功能移动到服务中。对了,你还需要重构数据库。

提取服务通常很耗时,尤其是当单体的代码库很混乱时。因此,你需要仔细考虑要提取的服务。应当重点关注重构那些能够提供很多价值的应用程序部分。在提取服务之前,问问自己这样做的好处是什么。

例如,提取一项实现对业务至关重要且不断发展的功能的服务是值得的。如果没有太多的好处,那么在提取服务方面投入精力是没有价值的。在本节的后面部分,我将介绍一些用于确定服务提取范围和时间的策略。但首先让我们更详细地了解一下在提取服务时将面临的一些挑战以及解决这些挑战的方法。

提取服务时会遇到以下这些挑战:

■ 拆解领域模型。

■ 重构数据库。

拆解领域模型

为了提取服务,你需要从单体的领域模型中提取服务相关的领域模型。你需要进行大动作来拆分领域模型。你将遇到的一个挑战是消除跨越服务边界的对象引用。保留在单体中的类可能会引用已移动到服务的类,反之亦然。例如,想象一下,如图 4 所示,你提取了Order Service,其Order类引用了单体的Restaurant类。因为服务实例通常是一个进程,所以让对象引用跨越服务边界是没有意义的。你需要消除这种类型的对象引用。

解决此问题的一个好方法是根据DDD聚合进行思考。聚合使用主键而不是对象引用相互引用。因此,你可以将 Order 和 Restaurant 类视为聚合,如图5所示,将Order类中对 Restaurant 的引用替换为存储主键值的restaurantId 字段。

使用主键替换对象引用的一个问题是,虽然这是对类的一个小改动,但它可能会对期望对象引用的类的客户端产生很大的影响。在本节的后面部分,我将介绍如何通过在服务和单体之间复制数据来减少更改的范围。例如,Delivery Service可以定义一个Restaurant类,后者是单体中Restaurant 类的复制品。

提取服务通常比将整个类移动到服务中的工作量要大得多。拆分领域模型面临的更大挑战是提取嵌入在具有其他职责的类中的功能。这个问题经常出现在具有过多职责的上帝类(God Class)中。例如,Order 类是FTGO应用程序中的上帝类之一。它实现了多种业务功能,包括订单管理、送餐管理等。Delivery 实体会实现之前与Order类中的其他功能捆绑在一起的送餐管理功能。

重构数据库

拆分领域模型不仅仅涉及更改代码。领域模型中的许多类都是在数据库中持久化保存的。它们的字段映射到具体的数据库模式。因此,当你从单体中提取服务时,你也会移动数据。你需要将表从单体的数据库移动到服务的数据库。

此外,拆分实体时,需要拆分相应的数据库表并将新表移动到服务中。例如,在将送餐管理提取到服务中时,你需要拆分Order实体并提取出一个Delivery实体。在数据库级别,你要拆分ORDERS表并定义新的DELIVERY表。然后,将DELIVERY表移动到该服务。

复制数据以避免更广泛的更改

如上所述,提取服务需要你对单体的领域模型做出更改。例如,使用主键和拆分类替换对象引用。这些类型的更改可能会影响代码库,并要求你对单体各个受影响的部分进行广泛的更改。例如,如果拆分Order实体并提取Delivery实体,则必须更改代码中引用被移动字段而受影响的每个部分。进行这些改变可能会非常耗时,并且可能成为打破单体的巨大障碍。

延迟并可能避免进行这些昂贵更改的一种好方法是使用类似于《数据库重构》一书中描述的方法。重构数据库的一个主要障碍是更改该数据库的所有客户端以使用新模式。本书中提出的解决方案是在过渡期内保留原模式,并使用触发器在原模式和新模式间同步。然后,你可以将客户端从旧模式迁移到新模式。

从单体中提取服务时,我们可以使用类似的方法。例如,在提取Delivery实体时,我们将Order实体在过渡期内大部分保持不变。如图6所示,我们将与交付相关的字段设置为只读,并通过将数据从Delivery Service复制回单体来使其保持***。因此,我们只需要在单体的代码中找到更新这些字段的位置,并更改它们为调用新的Delivery Service即可。

通过从Delivery Service复制数据来保留Order实体的结构,可以显著减少我们需要立即完成的工作量。随着时间的推移,我们可以将使用与交付相关的Order实体字段或ORDERS表列的代码迁移到Delivery Service。更重要的是,我们可能永远不需要在单体中做出改变。如果随后将该代码提取到服务中,则该服务可以访问DeliveryService。

确定提取何种服务以及何时提取

正如我所提到的,拆解单体是耗时的。它分散了实施新功能的人力资源。因此,你必须仔细确定提取服务的顺序。你需要专注于提取能够带来***收益的服务。更重要的是,你希望不断向业务部门展示迁移到微服务架构的价值。

在任何旅程中,了解你要去的地方至关重要。开始迁移到微服务的好方法是使用时间框架来定义工作。你应该花费很短的时间,例如几周,集思广益讨论理想架构并定义一组服务。这将为你提供一个目标。但是,重要的是要记住,这种架构并非一成不变。当你分解单体并获得经验后,你应该应用你所获得的经验对重构计划及时做出调整。

一旦确定了目标,下一步就是开始拆分单体结构。可以使用几种不同的策略来确定提取服务的顺序。

一种策略是有效地冻结单体架构的开发并按需提取服务。你可以提取必要的服务并进行更改,而不是在单体中实现功能或修复错误。这种方法的一个好处是它会迫使你打破单体。一个弊端是服务的提取是由短期需求而不是长期需求驱动的。例如,即使你对系统中相对稳定的部分进行了少量更改,也需要你提取服务。因此,你做的大量工作可能只能换来较小的收益。

另一种策略是更有计划的方法,你可以根据提取应用程序模块获得的预期收益,对应用程序的模块进行排名。提取服务有益的原因有以下几点:

■ 加速开发:如果你的应用程序的路线图表明应用程序的特定部分将在明年进行大量开发,那么将其转换为服务可加速开发。

■ 解决性能、可扩展性或可靠性问题:如果应用程序的特定部分存在性能、可扩展性问题或不可靠,那么将其转换为服务是有价值的。

■ 允许提取其他一些服务:由于模块之间的依赖关系,有时提取一个服务会简化另一个服务的提取。 你可以使用这些条件将重构任务添加到应用程序的“待办事项”中,并按预期收益排名。这种方法的好处在于它更具战略性,并且更符合业务需求。在做 Sprint 的计划时,你可以确定实现功能或提取服务哪个更有价值。

https://mp.weixin.qq.com/s/vkvYJnKfQyuUeD_BDQy_1g

获取更多学习资料,可以加群:473984645或扫描下方二维码

原文地址:https://www.cnblogs.com/lemonrel/p/11779025.html

时间: 2024-10-18 19:47:23

Java架构:一文读懂微服务架构的重构策略的相关文章

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们应该如何进行网络请求的优化与处理呢? 到底有没有一些好的建议与方案呢? 下面这个文章将揭晓上面的问题,让你对SpringCloud微服务网络请求性能有一个全新的认识. 目录简介 01.网络请求异常分类 02.开发中注意问题 03.原始的处理方式 04.如何减少代码耦合性 05.异常统一处理步骤 06

(转)微服务架构 互联网保险O2O平台微服务架构设计

http://www.cnblogs.com/Leo_wl/p/5049722.html 微服务架构 互联网保险O2O平台微服务架构设计 关于架构,笔者认为并不是越复杂越好,而是相反,简单就是硬道理也提现在这里.这也是微服务能够流行的原因,看看市场上曾经出现的服务架构:EJB.SCA.Dubbo等等,都比微服务先进,都比微服务功能完善,但它们都没有微服务这么深入民心,就是因为他们过于复杂.简单就是高科技,苹果手机据说专门有个团队研究如何能让用户更加简单的操作.大公司都是由小公司发展起来的,如果小

从经典架构项目中透析微服务架构的核心概念和充血模型

微服务架构和SOA区别 微服务现在辣么火,业界流行的对比的却都是所谓的Monolithic单体应用,而大量的系统在十几年前都是已经是分布式系统了,那么微服务作为新的理念和原来的分布式系统,或者说SOA(面向服务架构)是什么区别呢? 我们先看相同点: 需要Registry,实现动态的服务注册发现机制:需要考虑分布式下面的事务一致性,CAP原则下,两段式提交不能保证性能,事务补偿机制需要考虑:同步调用还是异步消息传递,如何保证消息可靠性?SOA由ESB来集成所有的消息:都需要统一的Gateway来汇

Re:从0开始的微服务架构--(二)快速快速体验微服务架构?--转

原文地址:https://mp.weixin.qq.com/s/QO1QDQWnjHZp8EvGDrxZvw 这是专题的第二篇文章,看看如何搭建一个简单模式的微服务架构. 记得好久之前看到一个大牛说过:如果单体架构都搞不好,就别搞微服务架构.乍一看,这句很有道理,后来发现这句话是不太对的,因为微服务架构的目的就是为了降低系统的复杂性,所以 微服务架构应该比单体架构更简单.更好实践才对. 这篇文章,我们就分享一下如何搭建一个 简单模式 的微服务架构. 什么是微服务架构的简单模式? 相对于大型互联网

一文读懂 Spring Boot、微服务架构和大数据治理三者之间的故事

微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物. 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物.互联网时代的产品通常有两类特点:需求变化快和用户群体庞大,在这种情况下,如何从系统架构的角度出发,构建灵活.易扩展的系统,快速应对需求的变化:同时,随着用户的增加,如何保证系统的可伸缩性.高可用性,成为系统架构面临的挑战.如果你想了解大数据的学习路线,想学习

Java高级架构:微服务架构的核心概念

微服务现在辣么火,业界流行的对比的却都是所谓的Monolithic单体应用,而大量的系统在十几年前都是已经是分布式系统了,那么微服务作为新的理念和原来的分布式系统,或者说SOA(面向服务架构)是什么区别呢? 我们先看相同点: 需要Registry,实现动态的服务注册发现机制: 需要考虑分布式下面的事务一致性,CAP原则下,两段式提交不能保证性能,事务补偿机制需要考虑: 同步调用还是异步消息传递,如何保证消息可靠性?SOA由ESB来集成所有的消息: 都需要统一的Gateway来汇聚.编排接口,实现

Spring Boot、微服务架构和大数据

一文读懂 Spring Boot.微服务架构和大数据治理三者之间的故事 https://www.cnblogs.com/ityouknow/p/9034377.html 微服务架构 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物.互联网时代的产品通常有两类特点:需求变化快和用户群体庞大,在这种情况下,如何从系统架构的角度出发,构建灵活.易扩展的系统,快速应对需求的变化:同时,随着用户的增加,如何保证系统的可伸缩性.高可用性,

企业应用架构之微服务架构

微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所以火热也是因为相对之前的应用开发方式有很多优点,如更灵活.更能适应现在需求快速变更的大环境. 本文将介绍微服务架构的演进.优缺点和微服务应用的设计原则,然后着重介绍作为一个"微服务应用平台"需要提供哪些能力.解决哪些问题才能更好的支撑企业应用架构. 微服务平台也是我目前正在参与的,还在研发过程中的平台产品,平台是以SpringCloud为基础,结合了普元多年来对企业应用的理解和产品的设计经验,逐步孵化的一个微服务应用平台. 目录:

微服务架构(Microservices)

说在前面 好久没写博文了,心里痒痒(也许是换工作后,有点时间了吧).最近好像谈论微服务的人比较多,也开始学习一下,但是都有E文,看起来半懂不懂的. Martinfowler的<微服务>,也算是入门必读了.有人翻译过,但是只有一半.还是自己练练手吧. 微服务 "微服务架构"一词在过去几年里广泛的传播,它用于描述一种独立部署的软件应用设计方式.这种架构方式并没有非常准确的定义,但是在业务能力.自动部署.端对端的整合.对语言及数据的分散控制上,却有着显著特征. "微服务