微服务进阶场景实战:BFF,如何缓解服务依赖复杂度的问题?

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 前面处理了服务间数据依赖的场景。除了这种频繁需要其他服务的数据的场景,其实还会碰到服务间依赖太杂乱的问题。本篇讨论的就是如何缓解服务依赖复杂度的问题。先把整个业务场景描述一下。

BFF

前面处理了服务间数据依赖的场景。

除了这种频繁需要其他服务的数据的场景,其实还会碰到服务间依赖太杂乱的问题。

本篇讨论的就是如何缓解服务依赖复杂度的问题。

先把整个业务场景描述一下。

业务场景:如何处理好微服务之间千丝万缕的关系

本节所讲的系统包含商品、订单、加盟商、门店(运营)、工单(门店)这几个服务,其他服务就不细说了。

除了一个App面向客户以外,还有一个App是给公司的员工和加盟商的员工使用的。里面有各种角色的用户,比如总部商品管理、总部门店管理、加盟商员工、门店人员等。当然,每个部门里面还会细分角色。

后台服务架构如图15-1所示。

网络异常,图片无法展示
|

• 图15-1 后台服务架构

其中,网关层负责如下工作。

1)路由:所有的请求都会通过网关层,网关层再根据URI把请求指向对应的后台服务,如果同一个服务有多个服务器节点,网关层还会做一些负载均衡的工作。

2)认证:对所有的请求进行集中认证鉴权。

3)监控:记录所有的API请求数据,API管理系统可以对API调用进行管理和性能监控。

4)限流熔断:当流量过大时,可以在网关层做限流。当后台服务出现响应延时或者故障时,可以主动熔断,保护后端的服务资源,同时,防止影响用户体验。

该架构看起来非常完美,有些类似于Spring Cloud标准架构,但它也存在一些问题。下面举两个例子。

1)有很多页面需要显示多个服务的数据。比如App首页,它要根据用户的不同来显示不同的信息。如果是门店运营人员,就要显示工单数量、最近的工单、销售订单数据、最近待处理的订单、低于库存安全值的商品等。

2)很多时候,用户的一个提交操作需要修改多个服务的数据。比如一个工单操作要修改库存、销售订单状态、工单的数据。

那么,第一个问题出现了:这两种情况要调用的接口做在哪个服务上?

接口设计过程中,经常需要纠结这个问题。当然,最终总能达成共识——第一个接口做在门店服务上,变成图15-2所示的调用关系;

第二个接口做在工单服务上,变成图15-3所示的调用关系。

网络异常,图片无法展示
|

• 图15-2 门店服务接口


网络异常,图片无法展示
|

• 图15-3 工单服务接口

接下来讲第二个问题。因为这样的需求非常多,所以服务经常会来回调用,最终服务调用关系就会变得纠缠不清,如图15-4所示。

网络异常,图片无法展示
|

• 图15-4 服务调用关系

这种复杂的依赖给迭代带来了地狱般的感受,这一点在第12章中有详细的描述,这里不再赘述。

所以总结一下,目前要解决两个问题。

1)对于很多页面要用的接口,都要考虑放在哪个后台服务,这导致决策效率低下,也导致一些职责划分不统一。

2)服务之间的依赖非常混乱。

为了解决这两个问题,项目组决定抽象出一个API层。

API层

一般来说,客户端的接口会有以下需求。

1)聚合:一个接口需要聚合多个后台服务返回的数据,然后再返回给客户端。

2)分布式调用:一个接口可能需要依次调用多个后台服务,去修改多个后台服务的数据。

3)装饰:一个接口需要重新装饰一下后台返回的数据,删除一些字段,或者对某些字段再加一个封装,组成客户端需要的数据。

项目组决定在客户端和后台服务之间增加一个新的API层,专门来做这些事情,此时架构如图15-5所示。

网络异常,图片无法展示
|

• 图15-5 API层架构

所有的请求经过网关后都由一个共用的API层进行处理,这个API层没有自己的数据库,它做的事情就是去调用其他后台服务。

这样的设计至少解决了两个问题。

1)纠结某个接口该放在哪个服务的情况大幅减少了。如果是聚合、装饰、分布式调用的逻辑,就都放在API层;如果是要落库或者查询数据库的逻辑,就看目标数据放在哪个服务,数据在哪里,逻辑就在哪里。

2)后台服务之间的依赖也大幅减少了。目前的依赖关系只有API层去调用各个后台服务,后台服务之间的调用关系减少了。

架构看起来更完美了一些,但是会面临新的问题。

客户端适配问题

一般来说,有一系列的接口给各种客户端调用,比如App、H5、PC网页、小程序等。正常来说,调用关系如图15-6所示。

网络异常,图片无法展示
|

• 图15-6 多种客户端调用关系

但是,这样的设计会有3个问题。

1)不同客户端的页面可能是不一样的,比如App的功能比较多,就会要求页面当中包含一些信息;小程序要求比较轻量化,同样的页面就会少一些数据。这样的问题会导致后台服务的同一个API需要为不同的客户端做不同的适配。

2)客户端经常做一些轻微的改动,比如加一个字段、减一个字段。客户端的接口都要求降低响应速度,为此需要遵循数据最小化原则。所以,伴随客户端这些细微但频繁的改动,后台服务也经常要发布新版本。

3)结合1)和2),后台服务的版本发布又要同时考虑不同客户端的兼容问题,无形中又增加了复杂度。

为了解决这些问题,可以考虑使用BFF。

BFF

(BackendforFront)BFF不是一个架构,而是一个设计模式。

它的主要理念是专门为前端设计优雅的后台服务(也就是API)。换句话说,就是每一种客户端有自己的API服务。这样调用关系就变成图15-7所示。

网络异常,图片无法展示
|

• 图15-7 使用BFF的调用关系

不同的客户端请求经过同一个网关后会分别重定向到专门为这种客户端设计的API服务(WX API即用于微信小程序的API)。

因为每个API服务只针对一种客户端,所以它们可以为特定的客户端进行优化,使得逻辑更轻便,而且响应速度会比一个通用的API服务更快(因为不需要判断不同客户端的逻辑)。

另外,每种客户端就可以自己发布,而不需要跟其他的客户端一起排期。

图15-7中的架构是通用的,但还需要通过深入研究具体业务来完善。

这次项目所针对的系统非常庞大,整个业务链条所涉及的工作都包含在这个系统中。前面列出了6个服务,但实际上系统的服务有近百个,由几百人组成的研发团队在维护这个系统,分为新零售、供应链、财务、加盟商、售后、客服等几个部门。

大家共同维护一个App,共同维护一个用户界面,新零售、售后、加盟商、客服还有各自的小程序和H5。

为了解耦和分开排期,每个部门肯定会维护自己的API服务,App与PC前端也要按部门实现组件化,此时的调用关系如图15-8所示。

网络异常,图片无法展示
|

• 图15-8 组件化后使用BFF的调用关系

这个架构基本上就是每个部门都会维护自己的一系列API服务。

接下来展开讨论一些细节问题。

技术架构上怎么实现

整套架构还是基于Spring Cloud实现,如图15-9所示。主要的3层分别如下。

1)网关:网关使用Spring Cloud Zuul。Zuul拉取注册到ZooKeeper的API服务,然后通过Feign调用API服务。

2)API服务:API服务是一个Spring Web服务。它没有自己的数据库,主要的逻辑就是聚合、分布式调用以及装饰数据。它通过Feign调用后台服务。

3)后台服务:后台服务也是Spring Web服务,它有自己的数据库和缓存。

网络异常,图片无法展示
|

• 图15-9 基于Spring Cloud的分层架构

API之间的代码重复怎么解决

一般来说,H5、小程序之间的需求都是不一样的。重复的代码逻辑主要存在于PC和App的API,因为它们有些页面功能是一样的,只不过布局不一样。针对这一点,几个部门有不一样的逻辑。

1)有的部门是将这些重复的代码放在一个JAR里面,让几个API服务共用。

2)有的部门是将这些重复的代码抽取在一个独立的称为CommonAPI的API服务中,其他API服务调用这个CommonAPI。

3)有的部门因为重复逻辑占少数,所以他们的做法就是保留这些重复代码。根据他们的评估,维护这些重复代码的成本会小于维护上述JAR或者CommonAPI服务的成本。如果有些API服务的出入参和后台服务提供接口的出入参一摸一样,该怎么办?

针对这种情况就会使用API服务的接口,其实就是一个简单的代理层,什么事都不用做。

那这些仅为代理的API接口能不能直接去掉呢?如果需要,有几个办法可以实现。

1)网关可以绕过API服务,直接调用后台服务,但是这样做就破坏了分层。

2)在API服务层做一个拦截器,如果这个URI找不到对应API服务中的controllermapping,就尝试直接通过URI去找后台的服务,有的话就直接调用。

第一个办法因为破坏了分层,很快就被否决了。项目组对第二个办法争执了很久,最终的结论是,这样做会增加系统的复杂度,出问题后调查起来很麻烦,而其好处只是去掉了一些看起来有些累赘的代码,从收益来说,并不会很大。而且这些代码的编写成本非常低,对整体的接口列表来说是可控的。综合考虑后,项目组决定,不去掉这些接口代码。

后台服务与API服务的开发团队如何分工

最后的分工是这样的:有一个专门的API团队负责这些API服务,后台的服务再根据领域来划分小组职责。

这样做的好处就在于,API团队对所有的服务有个整体的认识,由一个中心团队控制接口的划分,就不会出现后台服务划分不清楚、服务重复的情况。

当然,坏处就在于API团队整体业务逻辑偏简单一些,无法让人员长久在岗,所以也会定期进行岗位轮换。

小结

BFF这一章就讲完了。本章并不是介绍一个技术方案,而是整体接口开发的管理和设计方案,所以其内容基本都是一些设计思路和具体会碰到的场景。

另外,虽然本章关于BFF的内容只占一小部分,大部分是后台服务的分层设计,但是BFF的理念贯彻始终。

至此,微服务相关的架构已经讲完了,接下来将会进入开发运维场景实战,讨论如何让开发更高效。

本文给大家讲解的内容是微服务进阶场景实战:BFF,如何缓解服务依赖复杂度的问题?

相关文章
|
1月前
|
Cloud Native Java API
聊聊从单体到微服务架构服务演化过程
本文介绍了从单体应用到微服务再到云原生架构的演进过程。单体应用虽易于搭建和部署,但难以局部更新;面向服务架构(SOA)通过模块化和服务总线提升了组件复用性和分布式部署能力;微服务则进一步实现了服务的独立开发与部署,提高了灵活性;云原生架构则利用容器化、微服务和自动化工具,实现了应用在动态环境中的弹性扩展与高效管理。这一演进体现了软件架构向着更灵活、更高效的方向发展。
|
2月前
|
监控 负载均衡 安全
微服务(五)-服务网关zuul(一)
微服务(五)-服务网关zuul(一)
|
15天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
8天前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
43 4
|
14天前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
44 9
|
16天前
|
监控 安全 Java
构建高效后端服务:微服务架构深度解析与最佳实践###
【10月更文挑战第19天】 在数字化转型加速的今天,企业对后端服务的响应速度、可扩展性和灵活性提出了更高要求。本文探讨了微服务架构作为解决方案,通过分析传统单体架构面临的挑战,深入剖析微服务的核心优势、关键组件及设计原则。我们将从实际案例入手,揭示成功实施微服务的策略与常见陷阱,为开发者和企业提供可操作的指导建议。本文目的是帮助读者理解如何利用微服务架构提升后端服务的整体效能,实现业务快速迭代与创新。 ###
46 2
|
21天前
|
消息中间件 Kafka 数据库
微服务架构中,如何确保服务之间的数据一致性?
微服务架构中,如何确保服务之间的数据一致性?
|
18天前
|
运维 Kubernetes 开发者
构建高效后端服务:微服务架构与容器化技术的结合
【10月更文挑战第18天】 在数字化转型的浪潮中,企业对后端服务的要求日益提高,追求更高的效率、更强的可伸缩性和更易于维护的系统。本文将探讨微服务架构与容器化技术如何结合,以构建一个既灵活又高效的后端服务体系。通过分析当前后端服务面临的挑战,介绍微服务和容器化的基本概念,以及它们如何相互配合来优化后端服务的性能和管理。本文旨在为开发者提供一种实现后端服务现代化的方法,从而帮助企业在竞争激烈的市场中脱颖而出。
21 0
|
2月前
|
消息中间件 Kafka 数据库
微服务架构中,如何确保服务之间的数据一致性
微服务架构中,如何确保服务之间的数据一致性
|
2月前
|
运维 持续交付 API
深入理解并实践微服务架构:从理论到实战
深入理解并实践微服务架构:从理论到实战
128 3
下一篇
无影云桌面