实践

相关网站

微服务架构的优势(virtue):

简单说来,微服务是一种架构风格。通过对特定业务领域的分析与建模,将复杂的应用分解成小而专一、耦合度低并且高度自治的一组服务。微服务中的每个服务都是很小的应用,这些应用服务相互独立并且可部署。微服务通过对复杂应用的拆分,达到简化应用的目的,而这些耦合度较低的服务则通过 API 形式进行通信,所以服务之间对外暴露的都是 API,不管是对资源的获取还是修改。

  • Isolation 隔离状态
  • Autonomy 自治

BFF 前端的中间层后端

Backend for Frontends(以下简称 BFF) 顾名思义,是为前端而存在的后端 (服务) 中间层。引用了 BFF 之后,前端应用将直接和 BFF 通信,BFF 再和后端进行 API 通信,所以本质上来说,BFF 更像是一种“中间层”服务。

BFF 其实是一种 API Gateway 实现模式

API Gateway 的三种实现:

  • 一个 API Gateway 对所有客户端提供同一种 API,例:/api/users
  • 一个 API Gateway 通过 Router 对每种客户端提供分别的 API,例:/mobile/api/users/web/api/users
  • 多个 API Gateway 分别对每种客户端提供分别的 API,例:如上,但两个 Gateway 分别为 Mobile Gateway 和 Web Gateway。

BFF 其实是 API Gateway 的其中一种实现模式,即 BFF 更类似于第三种 API Gateway 实现,通常一个 BFF 对应一种客户端,再由 BFF 去调用后端的实际 API。

GraphQL 与 REST 对比

相比于 REST 风格,GraphQL 具有如下特性:

  1. 定义数据模型:按需获取
  2. 数据分层
  3. 强类型
  4. 协议而非存储
  5. 无须版本化

对于 GraphQL 和 REST 之间的对比,主要有如下不同:

  • 数据获取:REST 缺乏可扩展性, GraphQL 能够按需获取。GraphQL API 调用时,payload 是可以扩展的 ;
  • API 调用:REST 针对每种资源的操作都是一个 endpoint, GraphQL 只需要一个 endpoint( /graphql), 只是 post body 不一样 ;
  • 复杂数据请求:REST 对于嵌套的复杂数据需要多次调用,GraphQL 一次调用, 减少网络开销;
  • 错误码处理:REST 能够精确返回 HTTP 错误码,GraphQL 统一返回 200,对错误信息进行包装;
  • 版本号:REST 通过 v1/v2 实现,GraphQL 通过 Schema 扩展实现;

微服务 + GraphQL + BFF 实践

在微服务下基于 GraphQL 构建 BFF,例如在项目对应的业务场景下,微服务后台有近 10 个微服务,客户端包括针对不同角色的 4 个 App 以及一个 Web 端。对于每种类型的 App,都有一个 BFF 与之对应。每种 BFF 只服务于这个 App。BFF 解析到客户端请求之后,会通过 BFF 端的服务发现,去对应的微服务后台通过 CQRS 的方式进行数据查询或修改。

使用 GraphQL-express 框架构建项目的 BFF 端,然后通过 Docker 进行部署。BFF 和微服务后台之间,还是通过 registrator 和 Consul 进行服务注册和发现。

整体技术架构

三个 App 客户端分别使用 GraphQL 的形式请求对应的 BFF。BFF 层再通过 Consul 服务发现和后端通信。

关于系统中的鉴权问题

用户登录后,App 直接访问 KeyCloak 服务获取到 id_token,然后通过 id_token 透传访问 auth-api 服务获取到 access_token, access_token 以 JWT (Json Web Token) 的形式放置到后续 http 请求的头信息中。

在我们这个系统中 BFF 层并不做鉴权服务,所有的鉴权过程全部由各自的微服务模块负责。BFF 只提供中转的功能。BFF 是否需要集成鉴权认证,主要看各系统自己的设计,并不是一个标准的实践。

BFF is pary of Application, BFF 就是客户端的一部分

  • BFF 中定义的数据结构,就是客户端所真正关心的。
  • BFF 就是为客户端而生,是客户端的一部分。
  • 需要说明的是,对于“业务的关注”并不是说,BFF 会处理所有的业务逻辑,业务逻辑还是应该由微服务关心,BFF 关注的是客户端需要什么。

GraphQL Mutation 与 CQRS

不同于 query,所有 mutation 都会调用后端的 API,而后端的 API 对于资源的修改也是通过 SpringBoot EventListener 实现的 CQRS 模式。

新架构的测试

在引入了 BFF 的项目,我们的测试仍然使用金字塔原理,只是在客户端和后台之间,需要添加对 BFF 的测试。

  • Client 的 integration-test 关心的是 App 访问 BFF 的连通性,App 中所有访问 BFF 的请求都需要进行测试;
  • BFF 的 integration-test 测试的是 BFF 到微服务 API 的连通性,BFF 中依赖的所有 API 都应该有集成测试的保障;
  • API 的 integration-test 关注的是这个服务对外暴露的所有 API,通常测试所有的 Controller 中的 API。