API 组合技术完全指南

在微服务架构中,一个产品页面常常需要从多个独立服务中获取数据。如何优雅地将分散的数据汇聚成统一的响应?本文深度解析从客户端组合到边缘组合的 10+ 种模式与权衡。

API 组合问题

在基于微服务的架构中,一个单一的产品页面可能需要来自四个不同服务的数据:用户信息、最近的订单、配送状态和个性化推荐。每个服务只存储自己的数据,没有任何一个服务能独立返回完整结果。

调用方必须发出四次独立的调用,然后将四个响应合并为用户界面所需的结构。这种合并步骤就是 API 组合 (API Composition)。只要数据被拆分到多个服务中,API 组合就必然存在。

核心洞察

数据分散在多个服务中不是问题——问题是 谁来负责重新将它们组合在一起。这个决策影响延迟、可用性、缓存能力和团队协作。

组合代码在哪里运行?

执行合并操作的代码可以运行在多个位置:

服务端组合

  • 服务器间通信延迟极低(亚毫秒级)
  • 1次移动网络往返 + 4次数据中心往返
  • 可缓存完整的聚合响应
  • 可处理部分服务不可用的情况

客户端组合

  • 4次移动网络往返,延迟累积
  • 弱网环境下每个往返可达数百毫秒
  • 业务逻辑泄漏到客户端
  • 架构简单,无需额外基础设施

在移动应用和四个服务之间放置一个服务器会增加一次网络跳转,听起来像是会增加额外的时间。然而,它通常 减少 总加载时间:因为手机到服务器的一次往返在弱移动网络上可能需要几百毫秒,而同一数据中心内的服务间往返只需要不到一毫秒。简单来说,用一次昂贵的往返加上四次廉价往返来替换四次昂贵往返,通常是巨大的净节省。

然而,延迟只是第一个权衡点。合并操作的运行位置还决定了:当四个服务中的一个不可用时会发生什么、响应有多大程度可以被缓存、以及在上线前需要哪个团队的批准。

客户端侧组合

客户端侧组合是最原始也最直接的组合方式:由移动应用或浏览器直接调用多个后端服务,并在客户端完成数据合并。

工作原理

客户端应用感知到多个后端服务的存在,并为所需数据分别发起独立调用。每个调用返回一个子集数据,客户端代码负责将它们组装到正确的 UI 结构中。

移动客户端 用户服务 订单服务 配送服务 推荐服务 4 次独立网络请求(移动网络)

优势

架构简单

无需额外的服务端基础设施,客户端直接与后端服务通信。适合初期阶段或服务数量较少的场景。

劣势

高延迟累积

每次往返移动网络都需要数百毫秒。四个串行或非优化的并行请求会迅速导致秒级的加载时间。移动网络环境下的延迟问题尤为突出。

业务逻辑泄漏

合并逻辑写在客户端代码中,导致服务拆分与客户端紧耦合。当后端 API 发生变化时,必须同时更新所有客户端。

部分失败处理困难

当四个服务中有一个不可用时,客户端必须自行处理降级逻辑。这在原生移动应用中尤其难以维护。

过度获取与获取不足

当通用 API 服务于多个客户端时,两个经典问题随之出现:过度获取 (Over-fetching) 和获取不足 (Under-fetching)。

过度获取 (Over-fetching)

API 返回的数据远多于客户端实际需要的字段。

  • 移动端只显示用户头像和名字
  • API 返回了完整用户对象(50+ 字段)
  • 96% 下载的数据被浪费
  • 额外带宽消耗、电池损耗

获取不足 (Under-fetching)

一个 API 端点无法满足界面的数据需求,客户端必须发起多次调用。

  • 仪表盘需要用户 + 订单 + 活动
  • 需要3个独立的API调用来凑齐数据
  • 串行请求可导致 900ms+ 的加载时间
  • 客户端承担了编排责任
根本原因

问题根源在于:通用 API 无法同时满足所有客户端的独特需求。移动端和 Web 端对数据量、结构和粒度的要求天然不同。解决方案是引入一个中间层来为每个客户端"定制"响应。

组合、聚合与编排

这三个概念经常被混用,但它们代表不同的模式层次:

API 组合

将来自多个来源的数据合并成一个统一的响应结构。通常关注数据汇合而非业务逻辑。

示例:获取用户信息和最近订单,合并为单个JSON响应。

API 聚合

将多个调用"扇出"(fan-out)到不同服务并收集结果。通常是平行的、无状态的。

示例:并行调用三个服务,等待所有结果返回,然后合并。

API 编排

不仅聚合数据,还包含业务逻辑,可能有条件分支、状态管理和事务保证。

示例:先验证用户身份,然后从订单服务取数,再根据结果决定是否调用推荐服务。

关键区分

组合和聚合通常可以放在 API 网关或 BFF 中;而编排含有业务逻辑,通常属于核心业务服务。

API 网关

API 网关是位于客户端和后端服务之间的反向代理,作为所有 API 调用的单一入口点。它是 API 组合最经典的实现场所之一。

客户端 API 网关 用户服务 订单服务 配送服务 推荐服务 请求路由 · API 组合 · 协议转换 · 限流 · 认证

API 网关的核心功能

请求路由

将请求根据路径、标头或参数转发到对应的后端服务。例如 /api/users/* -> 用户服务。

API 组合

将多个后端服务的响应合并为单一的客户端响应。例如获取订单时同时获取订单项和配送状态。

协议转换

将不同的后端协议(gRPC、SOAP、WebSocket)转换为统一的前端协议(REST/JSON)。

边缘功能

在网关层实现认证、授权、限流、日志记录等横切关注点,统一治理。

API 网关的架构考量

关键风险

网关可能成为单点瓶颈。如果网关实现过于复杂(包含业务逻辑),它将退化为"分布式单体"的反模式。同时,每次增加组合逻辑都需要平台团队介入,可能成为交付瓶颈。

Backend for Frontends (BBF)

BFF 模式由 Sam Newman 在 SoundCloud 的实践中总结推广。其核心理念是:为每一种前端客户端类型创建一个专属的后端服务。

核心原则

"一个体验,一个 BFF。"——每个 BFF 只为一种客户端体验服务。移动端一个 BFF,Web 端一个 BFF,绝不共享。

BFF 的核心职责

请求聚合

将多个后端服务调用扇出(fan-out),然后合并响应。将 N+1 次客户端往返减少为 1 次。

响应整形

裁剪不必要的字段、重命名为客户端友好的名称、扁平化嵌套结构。只返回客户端真正需要的字段。

协议转换

Web BFF 可使用 REST/JSON,移动 BFF 可能使用 Protobuf 以减小负载大小。认证令牌转换也在这一层处理。

BFF 的聚合优势:N+1 -> 1 服务端

客户端聚合(优化前)

BFF 优化前(客户端聚合,5G网络):
客户端 -> GET /users/123 -> 用户服务 (200ms 5G)
客户端 -> GET /orders?userId=123 -> 订单 (200ms 5G)
客户端 -> GET /delivery?orderId=... -> 配送 (200ms 5G)
总计:600ms,3次移动网络往返
        

BFF 优化后

BFF 优化后(服务端聚合,千兆LAN):
客户端 -> GET /dashboard -> BFF (200ms 5G,1次往返)
BFF -> GET /users/123          (5ms 内网,并行)
BFF -> GET /orders?userId=123  (5ms 内网,并行)
BFF -> GET /delivery/status... (5ms 内网,并行)
BFF 合并 + 整形 (1ms)
总计:205ms,1次网络往返 — 快3倍
        

BFF vs API 网关:互补而非竞争

维度 API 网关 BFF
所有权平台/基础设施团队前端产品团队
范围所有客户端,所有服务一种特定客户端类型
逻辑复杂度薄层:路由、认证、限流丰富:组合、转换、业务适配
自定义程度通用的横切关注点高度定制化,匹配 UI 需求
部署方式每个环境一个网关每种客户端类型一个 BFF

在典型拓扑中:客户端 -> API 网关(认证、SSL终止、限流) -> BFF(组合、整形) -> 微服务

第7章

GraphQL 作为组合层

GraphQL 本质上就是一个 API 组合层。它的查询语言让客户端精确声明所需数据,服务端负责解析查询并聚合来自多个解析器的响应。

核心工作流

Schema 先行 · 类型安全

每个 GraphQL 服务定义一个类型架构(Schema)。客户端通过查询(Query)精确指定需要的字段。服务端通过解析器(Resolver)从多个下游服务获取数据。

GraphQL 组合的优势

精准数据获取

客户端只声明需要的字段,从根本上解决过度获取问题。一次查询即可获取来自多个服务的数据,也解决获取不足问题。

Schema Stitching & Federation

Schema Stitching:将多个 GraphQL 子图合并为一个统一架构。&bold;Apollo Federation:每个子图独立维护 schema,通过一个路由器组合成超级图(Supergraph)。

客户端 GraphQL 网关 子图 A 用户服务 子图 B 订单服务 子图 C 配送服务 查询解析 · Schema 组合 · 请求计划

Apollo Federation 架构

超级图(Supergraph)

通过 Apollo Federation,每个子图(Subgraph)独立维护其 schema。一个路由器(Router)作为单一访问点,通过组合所有子图 schema 形成超级图。客户端向路由器发送查询,路由器生成跨子图的执行计划。

边缘组合

边缘组合(Edge composition)指在 CDN 边缘节点或边缘计算平台上执行 API 组合逻辑,将数据聚合推向离用户最近的位置。

边缘组合的优势

超低延迟

CDN 边缘节点分布在数百个地理位置,用户从最近的节点获取数据。边缘计算延迟可低至 1-5ms。

全局缓存

在边缘节点缓存组合后的完整响应。对于热门内容,缓存命中率极高,大幅降低源站负载。

源站卸载

组合逻辑在边缘执行,源站只需关注业务逻辑和数据存储。DDoS流量被吸收在边缘节点处。

边缘组合的实现方式

Edge Workers / Lambda@Edge

CloudFlare Workers、AW Lambda@Edge 等服务允许在 CDN 边缘执行轻量级 JavaScript 代码。可以在请求过程中调用多个后端服务并合并结果。

权衡与局限

边缘节点的计算能力有限(CPU和内存受限)。复杂组合逻辑可能需要运行在中央服务器上。此外,边缘节点通常是无状态的,维护跨节点状态需要额外的基础设施。

可用性与缓存权衡

API 组合层的位置深刻影响系统的可用性和缓存能力。以下是在不同层面组合时的权衡矩阵:

场景 可用性 缓存能力 延迟
客户端组合低—任何服务故障导致UI显示不完整差—缓存分散在多个请求中高—取决于移动网络
API 网关组合中—网关可处理部分失败,返回部分数据好—可缓存完整聚合响应中—一次网络往返+数据中心内调用
BFF 组合中—BFF 可独立降级,不影响其他客户端好—每个 BFF 可针对客户端模式定制缓存策略低—预聚合后仅需一次客户端往返
GraphQL 组合中—路由器可向子图发送部分查询复杂—响应结构动态,缓存键设计挑战大中—查询计划可并行化子图调用
边缘组合高—多 POP 分布式,单点故障自切换极好—全球分布式缓存,边缘节点就近服务极低—就近获取,<5ms

缓存策略关键考量

TTL 权衡

较长 TTL 提高缓存命中率但增加数据过时风险;较短 TTL 保证数据新鲜度但降低缓存效率。可在组合层使用 stale-whle-revalidat 策略(RFC 5861)——先返回过时数据,同时在后台异步更新缓存。',

部分失败处理

当组合层调用的某个下游服务不可用时,组合层可以:(1)返回部分数据(其他成功服务的响应);(2)返回过时缓存数据;(3)返回一个友好的错误提示。选择取决于业务场景。

多前端版本管理

当 Web、iOS、Android 等多个前端共存时,版本管理变得复杂。不同前端可能运行在不同版本的 API 上——特别是移动端,用户可能不更新应用。

版本管理的挑战

移动端版本碎片化

用户不会立即更新应用。iOS 和 Android 上同时存在多个旧版本。新 API 必须向后兼容旧客户端。

Web 端快速迭代

Web 应用可以即时更新,不需要版本兼容。BFF 模式允许 Web BFF 快速演进,不影响移动端。

API 版本膨胀

如果通过 API 版本号(/v1/, /v2/)解决不同客户端需求,随着时间推移,维护多个 API 版本的历史负载会不断增加。

BFF 的版本管理策略

按客户端类型隔离版本

每个 BFF 独立管理其 API 版本。iOS BFF 的 v2 可以和 Web BFF 的 v5 同时存在,互不干扰。API 的向后兼容性只在同一 BFF 内部需要维护。

关键洞察:多客户端问题本质上是空间问题(不同端点同时有不同的需求),而非时间问题(同一端点在时间线上的变化)。API 版本号解决时间问题,BFF 解决空间问题。

组合层所有权

组合层由谁拥有和运营,对架构演进的敏捷性有深远影响。所有权模型决定了变更速度、沟通成本和责任边界。

所有权模型对比

平台团队所有(API 网关)

  • 集中治理,统一安全策略
  • 跨团队可见性
  • 变更需要经过平台团队
  • 前端的 API 需求可能排期滞后

前端团队所有(BFF)

  • 前端团队自主控制 API 形状
  • 变更可独立发布,不阻塞
  • 代码重复风险(各 BFF 可能有重复逻辑)
  • 需要前端团队具备后端能力
推荐实践

API 网关由平台团队运营,处理横切关注点(认证、限流、路由)。BFF 由前端产品团队所有,负责业务适配和组合逻辑。网关在前,BFF 在后,各司其职。

团队拓扑与 Conway 定律

Conway 定律指出:系统架构会镜像组织沟通结构。BFF 模式正是这一原则的体现——当前端团队拥有自己的后端时,跨团队协调成本大幅降低。Tamburr 等人的研究表明,BFF 所有权与前端团队边界对齐时,部署频率更高、变更失败率更低。

总结与决策指南

API 组合没有"万能钥匙"。选择哪种模式取决于你的服务规模、客户端多样性、团队结构和性能要求。

决策框架

场景 推荐模式 理由
仅 Web 端 + 2-3 个微服务API 网关简单直接,无需过多抽象
多客户端(Web + 移动 + API)BFF每个客户端获得定制的 API 形状
数据需求频繁变化GraphQL客户端自描述数据需求,无需后端配合
全球用户 + 高流量边缘组合就近计算 + 全局缓存 = 最低延迟
大型团队 + 正交职责网关 + BFF + GraphQL分层组合:网关(平台)-> BFF(产品)-> GraphQL(子图组织)
核心结论

1. API 组合是微服务架构中不可避免的问题。
2. 组合位置的选择影响延迟、可用性、缓存和团队协作。
3. 客户端组合虽然简单,但在移动网络下延迟不可接受。
4. API 网关适合处理横切关注点,但不应包含业务逻辑。
5. BFF 是处理多客户端问题的最实用模式。
6. GraphQL 作为组合层,提供最大的客户端灵活性。
7. 边缘组合正在崛起,适合全球分布的高性能场景。
8. 所有权模式决定架构演进速度——团队拓扑应与架构一致。

API组合技术