本文首发于我的微信公众号:coder小黑
服务拆分以后,先后端同窗之间关于 API 粒度的争吵愈来愈常见:前端
「前端同窗请求两个接口,聚合一下数据不就好了?」后端同窗想只提供业务领域基础 API 服务能力,数据组装处理则但愿由前端同窗完成。小程序
「后端聚合一下,前端能够少一次请求,只负责页面渲染!」前端同窗但愿只负责页面渲染,而 H五、APP、小程序同一个聚合逻辑可能会出如今三端,后端聚合则只须要一次。后端
接口聚合服务就是咱们的一个解决思路。api
接口聚合服务是什么?缓存
接口聚合服务就是一个搬运工,只是帮助前端同窗聚合多个接口的返回数据,聚合以后一次性返回相应请求的结果给客户端。咱们但愿经过接口聚合服务这个中间层,作到可让前端直接获取数据,然后端也能继续专心于提供基础业务领域 API 服务能力。微信
场景一:串行获取数据。多个请求,有关联关系。数据结构
场景二:并行获取数据。多个请求,无关联关系。框架
方案 A | 方案 B | |
---|---|---|
调用者 | 客户端 | 客户端 |
API-Server | 自研 | GraphQL |
Payload | 约定 | GraphQL |
Response | 约定 | GraphQL |
容错 | 约定 | 约定 |
动态选取字段 | 是 | 是 |
最终咱们选择了方案 A,经过自研一套简单的接口聚合中间层来解决这个问题。性能
因而,就有了接口聚合服务:api-aggregator。该框架有以下几个特色:ui
api-aggregator 认为一个聚合接口应该是由若干个接口的返回结果聚合而成的,所以在设计时,咱们将其被划分为两个部分:接口元信息和接口之间的聚合逻辑。
ApiDefinition 不只定义了接口的元信息,同时也描述了接口所需参数的来源。
api-aggregator 认为在一次接口聚合中,元信息接口的参数可能有如下一些来源:
ResponseDefinition 描述了接口间的聚合逻辑,经过 ResponseDefinition 前端同窗能够自定义接口返回的数据结构,也能够动态选取所需字段。
若是没有 ResponseDefinition,则 api-aggregator 只能简单的将两个接口的数据平级的聚合在一块儿(如上左图所示)。而如今,能够经过 ResponseDefinition 来定义返回结构体,给前端同窗更好的开发体验(如上右图所示)。
接口聚合配置信息是由前端开发同窗在管理后台配置的。
前端同窗在提交配置文件以后,api-aggregator 就会对配置文件作一些静态分析:分析接口的依赖状况,是否存在循环依赖等问题。
为了提升性能,api-aggregator 将相关的配置信息解析好以后,会直接缓存在内存中,以减小对同一份配置文件的反复解析,同时,再经过定时刷新和 MQ 的 pub/sub 来保证数据的一致性。
api-aggregator 抽象了 HttpMethodInvoker 来发起 HTTP 请求。经过 Supplier 来获取返回结果,屏蔽了不一样 Http Client 之间的 API 差别。
还记得前文提到的场景吗?
场景一:串行获取数据。多个请求,有关联关系。场景二:并行获取数据。多个请求,无关联关系。
在 api-aggregator 中,将这两个场景进行了简化合一。
首先, api-aggregator 在解析配置文件分析接口依赖时,会根据接口的依赖状况给出一个 api-aggregator 认为是最优的 HTTP 请求流程,而不是根据配置文件定义的接口顺序依次请求。
举个例子:
假设在一次接口聚合中,须要请求接口 A、B、C,而接口 B 的数据依赖于接口 A,接口 A 和接口 C 的请求参数都可直接从 HttpRequest 中获取参数。
那么,在实际的接口聚合过程当中,api-aggregator 会先请求接口 A 和接口 C,而后阻塞获取接口 A 的返回结果,最后请求接口 B。
api-aggregator 提供了 ApiAggregatePostProcessor 来方便后续扩展。
经过 ApiAggregatePostProcessor,api-aggregator 能够干预一个接口聚合的整个流程,例如:缓存接口信息、增长监控日志等等。
虽然经过 ApiAggregatePostProcessor 能够来干预接口的聚合流程,可是想要添加新的 Processor 时仍是须要重启api-aggregator。而 api-aggregator 做为接口聚合点,和网关类似,也是流量的集中点,在后续的版本中,可能会考虑引入 Groovy 脚本,来支持动态的开启和停用 Processor。
最后,欢迎你们在评论区一块儿留言讨论,感谢你的阅读~~
欢迎关注我的公众号: