前面我们使用 GraphQL 搭建了一个 BFF 单体服务。当业务越来越复杂,协作的团队越来越多,单体服务存在很多问题。我们现在介绍一种拆分方法。

单体服务

单体服务在业务规模较小的时候,开发效率很高,能够很好的满足业务的迭代诉求。但是,当业务规模逐步增长,特别是需要多个团队一起协作的时候,单体服务的一些问题就逐步显现出来了。

开发维护成本高

在业务规模比较小的时候,或者说业务成长初期,两三个人就可以支撑业务需求。当业务逐步扩大,领域模型越来越丰富,BFF 服务体量越来越大,单个开发人员已经无法掌握所有的领域模型,势必要在人员组织上做团队划分。

这时候,单体的 BFF 服务就开始面临多团队协作问题。具体会比现在这几个方面:

  • 代码规范问题

    不同的团队代码规范会有差异,揉在一个项目里非常混乱。

  • 模型管理问题

    BFF 的模型是对后端模型的映射,多个团队存在模型的重复定义问题。虽然能够通过充分沟通在一定程度上进行缓解,但也额外增加的沟通成本。

  • 沟通问题

    BFF 本身负责沟通前端和后端服务。划分团队以后,一次业务需求就需要多个团队一起开发 BFF 层,同一个项目要不停地确认各个分支的开发进度,并 merge 分支才能保证功能的正常。

发布效率低

除了对团队的协作问题外,多个需求并行开发,极大概率会导致 BFF 工程的发布冲突,造成发布拥堵问题。

举个例子加以说明。

订单侧进行了一次订单优化的日常更新,不涉及其他领域,在发布的当天,发现 BFF 项目被商品侧的需求占用,需要等待商品侧发布完成之后合并分支才能发布。

发布之前合并了分支,代码发生了变动,从质量的角度来看,就需要再做一次功能的回归验证。

如果在合并代码的时候还发生了代码冲突,那问题就会更加严重,直接给发布的质量带来隐患。

Apollo Federation

为了解决 BFF 单体服务的种种问题,我们需要对 BFF 进行拆分。

Apollo Federationopen in new window 给出了一个不错的拆分方案。

为什么不用 GraphQL Stitching?

GraphQL Stitching 也提供了服务拆分、子图 schema 拼接的能力。但是,相较于 Apollo Federation 申明式的 schema 定义、gateway 自动合并子图来说,GraphQL Stitching 需要手动调用 API 合并各个子图,这无疑会增加各服务之间的依赖,导致后期高昂的维护成本。

Federation 架构

uml diagram

Apollo Federation 架构主要包含两个部分,一个是领域服务,是整个 GraphQL 图中的一个子图。一个是网关,负责将所有的领域服务的子图拼合成一张完整的图。

用户的 GraphQL 请求都将指向网关,再由网关根据请求的 Query 分析,向后面的自服务发起请求,在所有子服务的请求都返回之后,Gateway 将这些请求合并,返回给用户。

使用了 Apollo Federation 以后,中间层被划分为两层。某一子服务负责某一具体领域的能力,定义该领域内的模型图。这样,人员组织的划分与具体的应用项目一一对应。

比如商品小组的同学负责开发维护商品子服务,订单小组的同学负责开发维护订单子服务。一个业务需求过来,就需要评估涉及的业务模块,叫上相关的开发同学一起评审,在评审的同时,开发同学就可以明确子服务之间交互的边界。比如订单如何调用商品等就可以在评审阶段明确。

服务拆分以后,订单服务的发布于商品服务的发布可以实现并行,互不干扰,大大提高了发布效率。

BFF 服务拆分后,Gateway 负责将这些领域定义的模型图拼合成一张整图,对外提供服务。Gateway 的能力与业务无关,不需要随业务迭代,只需要随着技术架构升级迭代即可,更新频次不高。

开发原则

  • 增量更新

Federation 架构通常不会在业务刚开始的时候就采用,因此就存在一个如何从单体应用升级到 Federation 架构的问题。

我们不建议将原有的单体服务进行一次彻底的重构,来升级到 Federation 架构。我们提倡增量更新,逐步的从原有服务中将子服务拆出来。

比如在一次需求迭代中,我们可以先将比较底层的商品子服务拆出来,独立成子服务上线。之后,在一次需求迭代中,将订单子服务拆出来,同时将查询商品的部分,切换到新的商品子服务上。

  • 通过业务领域划分子服务

通常在进行子服务拆分的时候,最直观的方法是通过类型拆分。

比如商品类型定义一个子服务,订单类型定义一个子服务。

这么划分虽然简单明确,但是会导致子服务数量太多。同时类型之间的关系错综复杂,一个业务需求会涉及到非常多的类型,从而导致每个子服务都需要更新。

我们提倡通过领域来划分子服务。商品领域内的模型都划分到商品子服务内。订单领域内的模型都划分到订单子服务内。

这样,业务能力是按领域内聚的,系统内的子服务数量也不会太多,与人员的组织结构可以相对应。

总结

本篇我们介绍了单体服务在业务规模逐渐扩大的时候遇到的问题。同时,我们也介绍了 Apollo Federation 的架构,以及在解决单体服务的问题时的一些开发原则。

关注微信公众号,获取最新推送~

加微信,深入交流~