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

简介: 前面处理了服务间数据依赖的场景。除了这种频繁需要其他服务的数据的场景,其实还会碰到服务间依赖太杂乱的问题。本篇讨论的就是如何缓解服务依赖复杂度的问题。先把整个业务场景描述一下。

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,如何缓解服务依赖复杂度的问题?

相关文章
|
4月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
810 3
|
2月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
2月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
6月前
|
缓存 负载均衡 监控
微服务架构下的电商API接口设计:策略、方法与实战案例
本文探讨了微服务架构下的电商API接口设计,旨在打造高效、灵活与可扩展的电商系统。通过服务拆分(如商品、订单、支付等模块)和标准化设计(RESTful或GraphQL风格),确保接口一致性与易用性。同时,采用缓存策略、负载均衡及限流技术优化性能,并借助Prometheus等工具实现监控与日志管理。微服务架构的优势在于支持敏捷开发、高并发处理和独立部署,满足电商业务快速迭代需求。未来,电商API设计将向智能化与安全化方向发展。
446 102
|
9月前
|
存储 NoSQL API
微服务——MongoDB实战演练——需求分析
本文档《5-MongoDB实战演练》聚焦于某头条文章评论业务的需求分析与功能实现。基于MongoDB,需完成以下功能:1)提供基本的增删改查API;2)支持通过文章ID查询相关评论;3)实现评论点赞功能。结合实际业务场景,演示MongoDB在数据存储与操作中的应用,附带示意图帮助理解业务结构。
147 2
微服务——MongoDB实战演练——需求分析
|
4月前
|
负载均衡 监控 Java
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
在微服务架构中,高可用与稳定性至关重要。本文详解熔断、限流与负载均衡三大关键技术,结合API网关与Hystrix-Go实战,帮助构建健壮、弹性的微服务系统。
541 1
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
|
9月前
|
NoSQL MongoDB 微服务
微服务——MongoDB实战演练——文章评论的基本增删改查
本节介绍了文章评论的基本增删改查功能实现。首先,在`cn.itcast.article.dao`包下创建数据访问接口`CommentRepository`,继承`MongoRepository`以支持MongoDB操作。接着,在`cn.itcast.article.service`包下创建业务逻辑类`CommentService`,通过注入`CommentRepository`实现保存、更新、删除及查询评论的功能。最后,新建Junit测试类`CommentServiceTest`,对保存和查询功能进行测试,并展示测试结果截图,验证功能的正确性。
211 2
|
9月前
|
NoSQL Java MongoDB
微服务——MongoDB实战演练——文章评论实体类的编写
本节主要介绍文章评论实体类的编写,创建了包`cn.itcast.article.po`用于存放实体类。具体实现中,`Comment`类通过`@Document`注解映射到MongoDB的`comment`集合,包含主键、内容、发布时间、用户ID、昵称等属性,并通过`@Indexed`和`@CompoundIndex`注解添加单字段及复合索引,以提升查询效率。同时提供了Mongo命令示例,便于理解和操作。
169 2
|
9月前
|
Java Maven 微服务
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的 maven 依赖
在项目中使用Swagger2工具时,需导入Maven依赖。尽管官方最高版本为2.8.0,但其展示效果不够理想且稳定性欠佳。实际开发中常用2.2.2版本,因其稳定且界面友好。以下是围绕2.2.2版本的Maven依赖配置,包括`springfox-swagger2`和`springfox-swagger-ui`两个模块。
405 0
|
9月前
|
NoSQL 测试技术 MongoDB
微服务——MongoDB实战演练——MongoTemplate实现评论点赞
本节介绍如何使用MongoTemplate实现评论点赞功能。传统方法通过查询整个文档并更新所有字段,效率较低。为优化性能,采用MongoTemplate对特定字段直接操作。代码中展示了如何利用`Query`和`Update`对象构建更新逻辑,通过`update.inc("likenum")`实现点赞数递增。测试用例验证了功能的正确性,确保点赞数成功加1。
203 0

热门文章

最新文章