微服务架构:拆分单体应用的难点

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 微服务架构:拆分单体应用的难点

5 拆分单体应用为服务的难点


从表面上看,通过定义与业务能力或子域相对应的服务来创建微服务架构的策略看起来很简单。但是,你可能会遇到几个障碍:

  • 网络延迟。
  • 同步进程间通信导致可用性降低。
  • 在服务之间维持数据一致性。
  • 获取一致的数据视图。
  • 上帝类阻碍了拆分。

让我们来看看每个问题,先从网络延迟开始。

 

网络延迟

 

网络延迟是分布式系统中一直存在的问题。你可能会发现,对服务的特定分解会导致两个服务之间的大量往返调用。有时,你可以通过实施批处理API在一次往返中获取多个对象,从而将延迟减少到可接受的数量。但在其他情况下,解决方案是把多个相关的服务组合在一起,用编程语言的函数调用替换昂贵的进程间通信。

 

同步进程间通信导致可用性降低

 

另一个需要考虑的问题是如何处理进程间通信而不降低系统的可用性。例如,实现createOrder()操作最常见的方式是让Order Service使用REST同步调用其他服务。这样做的弊端是REST这样的协议会降低Order Service的可用性。如果任何一个被调用的服务处在不可用的状态,那么订单就无法创建了。有时候这可能是一个不得已的折中,但是在第3章中学习异步消息之后,你就会发现其实有更好的办法来消除这类同步调用产生的紧耦合并提升可用性。

 

在服务之间维持数据一致性

 

另一个挑战是如何在某些系统操作需要更新多个服务中的数据时,仍旧维护服务之间的数据一致性。例如,当餐馆接受订单时,必须在Kitchen Service和Delivery Service中同时进行更新。Kitchen Service会更改Ticket的状态。Delivery Service安排订单的交付。这些更新都必须以原子化的方式完成。

 

传统的解决方案是使用基于两阶段提交(two phase commit)的分布式事务管理机制。但正如你将在第4章中看到的那样,对于现今的应用程序而言,这不是一个好的选择,你必须使用一种非常不同的方法来处理事务管理,这就是Saga。Saga是一系列使用消息协作的本地事务。Saga比传统的ACID事务更复杂,但它们在许多情况下都能工作得很好。Saga的一个限制是它们最终是一致的。如果你需要以原子方式更新某些数据,那么它必须位于单个服务中,这可能是分解的障碍。

 

获取一致的数据视图

 

分解的另一个障碍是无法跨多个数据库获得真正一致的数据视图。在单体应用程序中,ACID事务的属性保证查询将返回数据库的一致视图。相反,在微服务架构中,即使每个服务的数据库是一致的,你也无法获得全局一致的数据视图。如果你需要一些数据的一致视图,那么它必须驻留在单个服务中,这也是服务分解所面临的问题。幸运的是,在实践中这很少带来真正的问题。

 

上帝类阻碍了拆分

 

分解的另一个障碍是存在所谓的上帝类。上帝类是在整个应用程序中使用的全局类。上帝类通常为应用程序的许多不同方面实现业务逻辑。它有大量字段映射到具有许多列的数据库表。大多数应用程序至少有一个这样的上帝类,每个类代表一个对领域至关重要的概念:银行账户、电子商务订单、保险政策,等等。因为上帝类将应用程序的许多不同方面的状态和行为捆绑在一起,所以将使用它的任何业务逻辑拆分为服务往往都是一个不可逾越的障碍。


Order类是FTGO应用程序中上帝类的一个很好的例子。这并不奇怪:毕竟FTGO的目的是向客户提供食品订单。系统的大多数部分都涉及订单。如果FTGO应用程序具有单个领域模型,则Order类将是一个非常大的类。它将具有与应用程序的许多不同部分相对应的状态和行为。图6显示了使用传统建模技术创建的Order类的结构。


image.png


如你所见,Order类具有与订单处理、餐馆订单管理、送餐和付款相对应的字段及方法。由于一个模型必须描述来自应用程序的不同部分的状态转换,因此该类还具有复杂的状态模型。在目前情况下,这个类的存在使得将代码分割成服务变得极其困难。

 

一种解决方案是将Order类打包到库中并创建一个中央Order数据库。处理订单的所有服务都使用此库并访问访问数据库。这种方法的问题在于它违反了微服务架构的一个关键原则,并导致我们特别不愿意看到的紧耦合。例如,对Order模式的任何更改都要求其他开发团队同步更新和重新编译他们的代码。

 

另一种解决方案是将Order数据库封装在Order Service中,该服务由其他服务调用以检索和更新订单。该设计的问题在于这样的一个Order Service将成为一个纯数据服务,成为包含很少或没有业务逻辑的贫血领域模型(anemic domain model)。这两种解决方案都没有吸引力,但幸运的是,DDD提供了一个好的解决方案。

 

更好的方法是应用DDD并将每个服务视为具有自己的领域模型的单独子域。这意味着FTGO应用程序中与订单有关的每个服务都有自己的领域模型及其对应的Order类的版本。Delivery Service是多领域模型的一个很好的例子。如图7所示为Order,它非常简单:取餐地址、取餐时间、送餐地址和送餐时间。此外,DeliveryService使用更合适的Delivery名称,而不是称之为Order。


image.png


Order Service具有最复杂的订单视图,如图9所示。即使它有相当多的字段和方法,它仍然比原始版本的那个Order上帝类简单得多。


image.png


每个领域模型中的Order类表示同一Order业务实体的不同方面。FTGO应用程序必须维持不同服务中这些不同对象之间的一致性。例如,一旦OrderService授权消费者的信用卡,它必须触发在Kitchen Service中创建Ticket。同样,如果Kitchen Service拒绝订单,则必须在Order Service中取消订单,并且为客户退款。在第4章中,我们将学习如何使用前面提到的事件驱动机制Saga来维护服务之间的一致性。

 

除了造成一些技术挑战以外,拥有多个领域模型还会影响用户体验。应用程序必须在用户体验(即其自己的领域模型)与每个服务的领域模型之间进行转换。例如,在FTGO应用程序中,向消费者显示的Order状态来自存储在多个服务中的Order信息。这种转换通常由API Gateway处理,将在第8章中讨论。尽管存在这些挑战,但在定义微服务架构时,必须识别并消除上帝类。

 

我们现在来看看如何定义服务API。

 

6 定义服务API


到目前为止,我们有一个系统操作列表和一个潜在服务列表。下一步是定义每个服务的API:也就是服务的操作和事件。存在服务API操作有以下两个原因:首先,某些操作对应于系统操作。它们由外部客户端调用,也可能由其他服务调用。另次,存在一些其他操作用以支持服务之间的协作。这些操作仅由其他服务调用。

 

服务通过对外发布事件,使其能够与其他服务协作。第4章将描述如何使用事件来实现Saga,这些Saga可以维护服务之间的数据一致性。第7章将讨论如何使用事件来更新CQRS视图,这些视图支持有效的查询。应用程序还可以使用事件来通知外部客户端。例如,可以使用WebSockets将事件传递给浏览器。

 

定义服务API的起点是将每个系统操作映射到服务。之后确定服务是否需要与其他服务协作以实现系统操作。如果需要协作,我们将确定其他服务必须提供哪些API才能支持协作。首先来看一下如何将系统操作分配给服务。

 

把系统操作分配给服务

 

第一步是确定哪个服务是请求的初始入口点。许多系统操作可以清晰地映射到服务,但有时映射会不太明显。例如,考虑使用noteUpdatedLocation()操作来更新送餐员的位置。一方面,因为它与送餐员有关,所以应该将此操作分配给Courier Service。另一方面,它是需要送餐地点的DeliveryService。在这种情况下,将操作分配给需要操作所提供信息的服务是更好的选择。在其他情况下,将操作分配给具有处理它所需信息的服务可能是有意义的。表4显示了FTGO应用程序中的哪些服务负责哪些操作。


表4 FTGO应用程序的系统操作映射到具体的服务


image.png


把操作分配给服务后,下一步是确定在处理每一个系统操作时,服务之间如何交互。

确定支持服务协作所需要的API

 

某些系统操作完全由单个服务处理。例如,在FTGO应用程序中,Consumer Service完全独立地处理createConsumer()操作。但是其他系统操作跨越多个服务。处理这些请求之一所需的数据可能分散在多个服务周围。例如,为了实现createOrder()操作,Order Service必须调用以下服务以验证其前置条件并使后置条件成立:

 

  • Consumer Service:验证消费者是否可以下订单并获取其付款信息。
  • Restaurant Service:验证订单行项目,验证送货地址和时间是否在餐厅的服务区域内,验证订单最低要求,并获得订单行项目的价格。
  • Kitchen Service:创建Ticket(后厨工单)。
  • Accounting Service:授权消费者的信用卡。


同样,为了实现acceptOrder()系统操作,Kitchen Service必须调用Delivery Service来安排送餐员交付订单。表2-3显示了服务、修订后的API及协作者。为了完整定义服务API,你需要分析每个系统操作并确定所需的协作。


表5 服务、修订后的API及协作者


image.png


总结


  • 微服务中的服务是根据业务需求进行组织的,按照业务能力或者子域,而不是技术上的考量。

  • 有两种分解模式:

       按业务能力分解,其起源于业务架构。

       基于领域驱动设计的概念,通过子域进行分解。

 

  • 可以通过应用DDD并为每个服务定义单独的领域模型来消除上帝类,正是上帝类引起了阻碍分解的交织依赖项。
相关文章
|
9天前
|
运维 Cloud Native 持续交付
深入理解云原生架构及其在现代企业中的应用
随着数字化转型的浪潮席卷全球,企业正面临着前所未有的挑战与机遇。云计算技术的迅猛发展,特别是云原生架构的兴起,正在重塑企业的IT基础设施和软件开发模式。本文将深入探讨云原生的核心概念、关键技术以及如何在企业中实施云原生策略,以实现更高效的资源利用和更快的市场响应速度。通过分析云原生架构的优势和面临的挑战,我们将揭示它如何助力企业在激烈的市场竞争中保持领先地位。
|
8天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
7天前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
105 68
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
6天前
|
运维 监控 持续交付
微服务架构解析:跨越传统架构的技术革命
微服务架构(Microservices Architecture)是一种软件架构风格,它将一个大型的单体应用拆分为多个小而独立的服务,每个服务都可以独立开发、部署和扩展。
88 36
微服务架构解析:跨越传统架构的技术革命
|
9天前
|
设计模式 负载均衡 监控
探索微服务架构下的API网关设计
在微服务的大潮中,API网关如同一座桥梁,连接着服务的提供者与消费者。本文将深入探讨API网关的核心功能、设计原则及实现策略,旨在为读者揭示如何构建一个高效、可靠的API网关。通过分析API网关在微服务架构中的作用和挑战,我们将了解到,一个优秀的API网关不仅要处理服务路由、负载均衡、认证授权等基础问题,还需考虑如何提升系统的可扩展性、安全性和可维护性。文章最后将提供实用的代码示例,帮助读者更好地理解和应用API网关的设计概念。
37 8
|
14天前
|
消息中间件 运维 Kubernetes
后端架构演进:从单体到微服务####
本文将探讨后端架构的演变过程,重点分析从传统的单体架构向现代微服务架构的转变。通过实际案例和理论解析,揭示这一转变背后的技术驱动力、挑战及最佳实践。文章还将讨论在采用微服务架构时需考虑的关键因素,包括服务划分、通信机制、数据管理以及部署策略,旨在为读者提供一个全面的架构转型视角。 ####
27 1
|
14天前
|
运维 Kubernetes Docker
深入理解容器化技术及其在微服务架构中的应用
深入理解容器化技术及其在微服务架构中的应用
31 1
|
7天前
|
Cloud Native API 持续交付
云原生架构下的微服务治理策略与实践####
本文旨在探讨云原生环境下微服务架构的治理策略,通过分析当前面临的挑战,提出一系列实用的解决方案。我们将深入讨论如何利用容器化、服务网格(Service Mesh)等先进技术手段,提升微服务系统的可管理性、可扩展性和容错能力。此外,还将分享一些来自一线项目的经验教训,帮助读者更好地理解和应用这些理论到实际工作中去。 ####
17 0
|
27天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
17天前
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
33 3