其他

BFF——服务于前端的后端

场景


关于前后端日常描述:
后端同学追求的服务下沉,解耦,微服务化。一条message 需要几个接口返回。[前端:能给组装一下吗?, 后端:都返你了,自己拼一下吧…别人也这么用的…]
前端追求用户体验 [前端:少一次http请求,多写个接口难吗? 后端:没必须浪费时间在重写,不差这个一个请求…]
总结: 前端和后端同学都说的各自有道理,就看谁有时间来处理了,那到底有没有一种解决场景可以化解这种尴尬的场景,于是就有了BFF。

什么是BFF?


BFF是服务于前端的后端,全称Backend For Frontend。BFF的位置在与客户端与服务端中间,起到一个中间件的作用。

让我们看下结构分布图如下:

解析此图可以简单看出:BFF将服务端的接口数据汇聚一块,然后经过整理加工传给前端。这样前端就可以直接调用一个接口就能直接获取数据。而后端也不至于为前端的需要而将业务代码汇聚到一块。方便了前后端开发。BFF向下是服务端各种微服务,向上则是为客户端提供接口服务。后端为BFF层的前端提供的 RPC 接口, BFF 层则直接调用服务端 RPC 接口拿到数据,按需加工数据,来完成整个BFF的闭环(以Node+GraphQL技术栈为主)

BFF层 发挥着 UI适配层和API聚合层,主要是跟进UI的迭代,对后端的接口进行组合、拆分、分化、聚合等。
在BFF层下面是各种后端的服务,如:订单、支付、购物车等,向上给客户端提供接口,后端为前端提供RPC接口,BFF层则可以直接调用服务RPC接口拿到数据,按照自己需要进行数据加工。
BFF 谁使用 谁开发 谁维护 谁出事 谁背锅,意味着前端同学要挑起重任,离“全栈工程师” 又进一步。

BFF解决了什么问题?


BFF,即 Backend For Frontend(服务于前端的后端),也就是服务器设计 API 时会考虑前端的使用,并在服务端直接进行业务逻辑的处理,又称为用户体验适配器。BFF 只是一种逻辑分层,而非一种技术。

如下图,在我们的前端页面时常存在,某个页面需要向 backend A、backend B 以及 backend C… 发送请求,不同服务的返回值用于渲染页面中不同的 component,即一个页面存在很多请求的场景。

此时,每次访问该页面都需要发送 3 个请求。同时为了保障 Android,iOS,以及 Web 端的不同需求,需要为不同的平台写不同的 API 接口,而每当值发生一些变化时,需要 Android,iOS,Web 做出修改。与此同时,当我们需要对一个字符串进行处理,如限定 140 个字符的时候,我们需要在每一个客户端(Android,iOS,Web)分别实现一遍,这样的代价显然相当大。

于是,我们就需要 BFF 作为中间件。在这个中间件上我们将做一些业务逻辑处理:

而当我们有了 BFF 这一层时,我们就不需要考虑系统后端的迁移。后端发生的变化都可以在 BFF 层做一些响应的修改。

例如,我们加入 BFF 层,原本每次访问发送 3 请求页面,变成一个请求。

使用 BFF 的正确姿势


  • 多端应用

我们在设计 API 时会考虑到不同设备的需求,也就是为不同的设备提供不同的 API,虽然它们可能是实现相同的功能,但因为不同设备的特殊性,它们对服务端的 API 访问也各有其特点,需要区别处理。

  • 服务聚合

随着微服务的兴起,原本在同一个进程内运行的业务流程被拆分到了不同的服务中。这在增加业务灵活性的同时,也让前端的调用变得更复杂。BFF 的出现为前端应用提供了一个对业务服务调用的聚合点,它屏蔽了复杂的服务调用链,让前端可以聚焦在所需要的数据上,而不用关注底层提供这些数据的服务。

  • 非必要,莫新增

我们在看到 BFF 带来的各种好处的同时,也要注意到它所带来的代码重复和工作量增加方面的问题。如果与已有 BFF 功能类似,且展现数据的要求也相近的话,一定要谨慎对待新增 BFF 的行为。因此,建议非必要,莫新增。

实战中的玩法


  • 访问控制

例如,服务中的权限控制,将所有服务中的权限控制集中在 BFF 层,使下层服务更加纯粹和独立。

  • 应用缓存

项目中时常存在一些需要缓存的临时数据,此时 BFF 作为业务的汇聚点,距离用户请求最近,遂将该缓存操作放在 BFF 层。

  • 第三方入口

在业务中需要与第三交互时,将该交互放在 BFF 层,这样可以只暴露必要信息给第三方,从而便于控制第三方的访问。

前端演化史


  1. Web 1.0

故事都得从long long ago说起,让我们先来回顾web 1.0,那时候的网站如下所示:

第一代Web架构很简单,纯后端网页渲染;就是客户端每次向服务器请求都会返回一个特定的html页面,js都没啥大用场。我学生时代流行的JSP就属于这个范畴。后来上班了,发现厂里的操作更风骚,用的是string拼接html的动态渲染技术,当时极为震惊。

2.Web 2.0

时间又到了10年前,手机业务开始蓬勃发展;受限于网络传输,由后端反复送html到前端(后端渲染)的技术很难适应新的业务场景。

这时候聪明的小伙子们想到了将数据格式转化成JSON,并通过api调用提供给前端使用——前后端解耦。

此后的变化是一系列的JS前端框架方兴未艾;得益于技术演进,前后端技术正式分离,Web交互空前丰富。

3.微服务时代

前端在剧烈演进,后端也悄然发生着变化:微服务、中台战略这类词汇充斥在各类技术架构中。

  • API Gateway

比较直观的方案就是利用api网关分发请求:

  • CORS

第二个想到的是前端跨域请求。前端分别向不同微服务发出请求,再将回调数据在Flux层处理后反映在DOM上。

上述两种方案,在业务权责上有明显偏重。怎么看出来呢?看数据的组装、聚合、裁剪放在哪一块就行了。

做过前端的小伙伴一般都能理解这一点:网页各个子模块的展示是很琐碎的:有时是一个单一字符串的显示,有时是多表联结的表单渲染。

在方案一中,后端有时需要准备力度很细的数据返回,这个就要求前后端频繁沟通。而另一些场景,后端又需要构造各种级联表单,以致微服务之间调度频繁;而微服务的本质是清晰的界限上下文,因此在某些场景下这种设计会导致领域建模变得较为复杂。

再说一下方案二。前端分层建模是最近比较流行的设计趋势,有一些流派甚至喊出了前端DDD,我也挺喜欢这种趋势的。说实在,后端编写接口挺麻烦的,不如提供一些粗粒度的api,交由前端酌情处理。只是传输负载可能会比较大;还有就是在多平台开发时,各平台需要重复组织数据,这就显得很冗余了。

  • BFF

有没有更优雅的解决方式呢?嗯,不如将组装、聚合、裁剪这部分业务单独拎出来,组成一个叫Back-end for Front-end的中间层。

    没有什么是加一个中间层解决不了的,如果有,就加两个…… ——鲁迅

BFF就是老生长谈的中间层概念,是上述一二方案的折衷解法。实现上没太大限制,就是一层nodejs,能做请求转发和数据转化即可。Nodejs既配合了前端技术栈,也更适应向微服务的并发请求。我自己的项目就是在Node上跑了一个Graphql的服务;也可以做成对前Restful、对后RPC的实现;还可以在BFF上加cache、鉴权等等操作,具体可以根据自身需求改造。

BFF优缺点


回顾完前端演化史,我们再来分析BFF利弊。

BFF作为中间层,优点是:

  • 前后端彻底分离,即便是后期有微服务迁移,也不需改动前端代码
  • 业务更向前靠拢,琐碎的api由前端开发自己决定,更适配前端框架
  • BFF可以自开mock,插件也能生成API文档,相比后端单开这类服务要方便些吧
  • 留给后端更清晰的服务边界,只需要提供粗粒度的接口即可
  • 应用缓存,可以增加一些缓存临时数据,更快的响应数据。
  • 性能优化,高并发与负载均衡:常见的情况下,高并发的性能制约包括了大量的I/O操作时CPU利用率较低,而Node在处理I/O密集型操作时有自己的优势。
  • UI多端适配,展示不同数据,灵活配置同一个接口,对接口做额外处理,PC端与移动端可以自由调节字段,同时也能聚会API来减少HTTP请求。
  • 访问控制,可以把服务中的权限集中控制在BFF层,使下层服务更加纯粹和独立

当然,BFF的缺点也很明显——增加了系统的复杂度,这会导致一系列的连锁反应

  • 中间层转发会增加请求延迟。
  • 需要保证端到端测试
  • 必须随时准备好后端异常请求
  • BFF分成会增加开发成本
  • 维护问题:需要维护各种 BFF 应用、以往前端也不需要关心并发,现在并发压力却集中到了 BFF 上
  • 重复开发:在开发一个BFF的应用的时候,会出现重复开发BFF的问题展示。增加了开发成本。
  • 链路复杂:在BFF的流程中,不仅要兼顾客户端还要兼顾服务端,这样就导致了一个流程的繁琐。
  • 浪费资源:现在多了一个BFF层,因此资源上的消耗也会比之前多。
  • 维护成本增加:在开发BFF应用中,要对BFF进行维护。
  • 分布式事务(微服务的通病)
  • 链路复杂:流程变得繁琐、BFF引入后,要同时走前端、服务端的研发流程,多端发布、互相依赖,导致流程繁琐浪费

总结



BFF层并不是一定适用,虽然技术提升了,但是相应的问题也暴露了,所以前端想做BFF中的中间层,需要了解更多,同时也抢了一部分后端的“饭碗”,后来SSR出现了 更加扩大了BFF层的使用,BFF层有利有弊,要看自己的业务来选择,现在有很多的BFF层通过

  • 处理复杂的数据可视化主要Node+GraphQL技术栈为主。
  • 提升用户体验的主要是以node+SSR技术为主