软件架构场景之——BFF:如何处理好微服务之间千丝万缕的
关系?
业务场景
之前设计的⼀个供应链系统中,它包含了商品、销售订单、加盟商、门店运营、门店⼯单等服务,涉及了各种⽤户⾓⾊,⽐如总部商品管理、总部门店管理、加盟商员⼯、门店⼈员等,⽽且每个部门的⾓⾊还会进⾏细分。⽽且这个系统中还包含了两个客户端 App:⼀个⾯向客户,另⼀个⾯向公司员⼯和加盟商
此时,整个供应链系统的架构如下图所⽰
上图中的⽹关层主要负责路由、认证、监控、限流熔断等⼯作
此时,架构看起来是不是挺完美?且市⾯上标准的 Spring Cloud 架构都是这样做的。不过,这个架构会出现⼀些问题,下⾯先通过⼏个例⼦来看看
案例⼀:
在这个供应链系统中,很多界⾯都需要显⽰多个服务数据,⽐如在⼀个 App ⾸页中,针对门店运营⼈员,需要显⽰⼯单数量、最近的⼯单、销售订单数据、最近待处理的订单、低于库存安全值的商品等信息
此时第⼀个问题来了,在接⼝设计过程中,经常纠结将两个客户端 App 调⽤的接⼝存放在哪个服务中?以⾄于决策效率低下,⽽且还会出现职责划分不统⼀的情况
最终决定将第⼀个接⼝存放在门店服务中,此时调⽤关系如下图所⽰
并将第⼆个接⼝存放在⼯单服务中,此时调⽤关系如下图所⽰
案例⼆:
⼀个⽤户的提交操作常常需要修改多个服务数据,⽐如⼀个提交⼯单的操作,我们需要修改库存、销售订单状态、⼯单等数据
此时第⼆个问题出现了,因为这样的需求⾮常多,所以服务经常被其他多个服务调来调去,导致服务之间的依赖⾮常混乱,最终服务调⽤关系如下图所⽰
通过上图,发现服务间的依赖问题给技术迭代带来了地狱般的体验,为了解决这 2 个问题,最终决定抽象⼀个 API 层
API 层
⼀般来说,客户端的接⼝需要满⾜聚合、分布式调⽤、装饰这三种需求
因此,决定在客户端与后台服务之间增加⼀个新的 API 层,专门⽤来满⾜上⾯的三点需求,此时整个架构如下图所⽰
分布式和微服务的关系从图中我们发现,所有请求经过⽹关后,全部交由⼀个共⽤的 API 层进⾏处理,⽽该 API 层没有⾃⼰的数据库,它的主要职责是调⽤其他后台服务
通过这样的设计⽅案后,以上两个问题就得到了很多地解决
客户端适配问题
在这个供应链系统中,⼀系列的接⼝主要供各种客户端(⽐如 App、H5、PC ⽹页、⼩程序等)进⾏调⽤,此时的调⽤关系如下图所⽰
不过,这种设计⽅案会存在 3 个问题
这时该如何解决呢?我们就可以考虑使⽤ BFF 了
BFF(Backend for Front)
BFF 不是⼀个架构,⽽是⼀个设计模式,它的主要职责是为前端设计出优雅的后台服务,即⼀个 API。⼀般⽽⾔,每个客户端都有⾃⼰的API 服务,此时整个架构如下图所⽰
从上图可以看到:不同的客户端请求经过同⼀个⽹关后,它们都将分别重定向到为对应客户端设计的 API 服务中。因为每个 API 服务只能针对⼀种客户端,所以它们可以对特定的客户端进⾏专门优化。⽽去除了兼容逻辑的 API 显得更轻便,响应速度还⽐通⽤的 API 服务更快(因为它不需要判断不同客户端的逻辑)
除此之外,每种客户端还可以实现⾃⼰发布,不需要再跟着其他客户端⼀起排期
此时的⽅案挺完美了吧?还不完美,因为上⾯的⽅案属于⼀个通⽤架构。在实际业务中,还需要结合实际业务来定,下⾯深⼊说明⼀下实际业务需求
前⾯列出了 5 种服务,实际上,整个供应链系统将近有 100 种服务。因为它是⼀个⾮常庞⼤的系统,且整个业务链条的所有⼯作都包含在这个系统中,⽐如新零售、供应链、财务、加盟商、售后、客服等,这就需要⼏百号研发⼈员同时进⾏维护
因为共同维护⼀个 App、PC 界⾯、新零售、售后、加盟商,还有各⾃的⼩程序和 H5,所以为了实现业务解耦和分开排期,每个部门需要各⾃维护⾃⼰的 API 服务,⽽且 App 与 PC 前端也需要根据部门实现组件化,此时的架构如下图所⽰
技术架构上如何实现?
整套架构还是基于 Spring Cloud 设计的,如下图所⽰