API 网关专栏 · 第 70 章

大规模 SaaS 平台的 API 网关架构

2026年09月15日
大规模 SaaS 平台的 API 网关架构

大规模 SaaS 网关应把经过验证的租户身份转换为有边界的路由、配额和可观测上下文,同时把领域授权与数据隔离留给真正拥有它们的服务。它还必须限制故障半径:单个租户、区域、配置变更或依赖故障不能耗尽整个平台。

网关只是隔离体系中的一层,并不等于完整的多租户设计。它可以认证、路由、限流并为请求添加标签,却无法单独证明行级隔离、让所有后端自动感知租户,或创造下游并不存在的容量。

核心要点

  • 租户上下文必须来自已验证凭证和服务端映射,绝不能直接信任公网租户请求头。
  • 分别为请求、并发、高成本操作和共享依赖设置隔离预算。
  • 当单一全局故障域不可接受时,应把数据面划分为多个 Cell 或区域。
  • 策略配置既要足够集中,便于治理;也要有明确作用域,避免错误变更影响所有租户。
  • 按依赖项选择故障放行或故障关闭,并记录两条路径;不能以可用性为由无条件绕过隔离。

从租户信任边界开始

只有明确来源,“租户 ID”才有意义。客户端可能通过主机名、路径、请求头、API Key 或 Token Claim 表达租户。网关必须先验证凭证,再把它映射为内部租户标识符。RFC 8725 要求实现不要在未验证的情况下信任收到的 JWT Claim,验证范围包括签发者、受众、签名和应用专用规则。

采用以下顺序:

1sequenceDiagram
2    participant C as 客户端
3    participant G as API 网关
4    participant I as 身份提供商或可信密钥源
5    participant T as 权威租户目录
6    participant S as SaaS 服务
7    participant D as 租户感知数据层
8    C->>G: 请求、凭证和声明的上下文
9    G->>I: 获取身份响应或可信验证密钥
10    I-->>G: 身份响应或密钥
11    G->>G: 验证签名、签发者、受众和凭证状态
12    G->>T: 把已验证主体映射到允许的租户
13    T-->>G: 权威租户与 Cell 映射
14    G->>G: 用可信上下文替换公网租户提示
15    G->>S: 请求和网关生成的租户上下文
16    S->>S: 执行对象与工作流授权
17    S->>D: 在权威租户边界内查询
18    D-->>S: 租户范围内的结果
19    S-->>G: 响应
20    G-->>C: 响应

如果公网 X-Tenant-ID 请求头对路由有帮助,应把它与验证后的映射比较,再覆盖或拒绝它,不要向后端转发两个互相冲突的值。服务只能通过经过认证、无法被调用方绕过的内部路径信任网关生成的上下文。

分层构建隔离

层级网关责任仍由其他组件负责的内容
身份验证受支持凭证并创建最小可信上下文账户生命周期、租户成员关系、撤销策略
准入执行请求、并发、负载和成本边界保护 Worker、队列、数据库连接池和第三方开支
路由选择区域、Cell、API 版本和服务保持租户位置权威且一致
数据阻止明显跨租户路由并移除不可信上下文执行行、Schema、数据库或账户隔离
可观测性输出对租户安全的路由和策略结果控制敏感字段、保留周期、审计和事件访问
配置应用已审查的策略制品审批权益、例外和业务策略

限流只是其中一种预算。租户可能没有超过 RPS 限制,却耗尽长连接、数据库锁、AI 推理费用或缓慢的第三方 API。至少应定义请求速率、并发、负载大小和高成本操作预算,并与下游容量对齐。

选择数据面拓扑

共享区域集群

共享集群简单且资源效率高,适合租户数量较少、策略相似的工作负载。它的风险是故障域较大:错误插件、路由、配置或流量高峰可能影响许多租户。

Cell 化集群

Cell 把一部分租户分配给独立网关与服务容量。全局目录把经过验证的租户映射到 Cell;每个 Cell 负责这部分租户的路由、配额和后端。Cell 可以缩小故障半径,也更容易推算容量,但租户放置、迁移和跨 Cell 操作会成为平台责任。

1flowchart TB
2    C[客户端] --> E[全局边缘与租户路由]
3    E --> A[Cell A 网关]
4    E --> B[Cell B 网关]
5    A --> AS[Cell A 服务与数据]
6    B --> BS[Cell B 服务与数据]
7    P[已审查的策略源] --> PA[Cell A 控制路径]
8    P --> PB[Cell B 控制路径]

全局边缘必须根据已验证的位置数据路由,不能依赖调用方选择的 Cell 请求头。控制路径负责分发配置,不承载用户请求。

租户专属集群

监管、网络、性能或合同隔离要求可能需要租户专属网关,但其运维成本更高,也可能造成配置漂移。除非某个租户有明确且有文档的差异化要求,否则应与共享 Cell 使用同一策略源、验证和可观测契约。

在 APISIX 中谨慎应用租户配额

Apache APISIX 3.18.0 提供 Consumer Group,用于在多个 Consumer 之间共享插件配置;limit-count 插件则支持本地或基于 Redis 的计数器。Consumer Group 可以代表运营策略组或租户,但不能替代应用数据隔离。

下面的 JSON 是租户范围 Consumer Group 的配置片段。它假设认证已经选出合法绑定到 tenant-acme 的 Consumer;调用方不能直接选择 group_id。

1{
2  "plugins": {
3    "limit-count": {
4      "count": 200,
5      "time_window": 60,
6      "policy": "redis",
7      "redis_host": "redis.internal",
8      "redis_port": 6379,
9      "key_type": "constant",
10      "key": "tenant-acme",
11      "group": "quota-tenant-acme",
12      "allow_degradation": false,
13      "rejected_code": 429
14    }
15  }
16}

key_type: constant 和 key: tenant-acme 会让绑定到这个租户专属 Consumer Group 的所有已认证 Consumer 共用同一个配额键。另一个 group 字段用于让匹配的插件配置跨路由共享该计数器,并不能替代计数键。如果省略 key_type 和 key,APISIX 3.18 会默认使用 var 和 remote_addr,结果是每个来源 IP 各有一份配额,而不是整个租户共享一份配额。这个常量之所以可信,是因为运维方在 Consumer Group 配置中从服务端设定它,而认证只会选择已绑定到该组的 Consumer;绝不能根据公网租户请求头生成它。

此配置片段有意省略 Redis 凭据和传输安全配置。生产环境必须按照固定版本的插件文档配置 Redis 认证与 TLS。

allow_degradation 会改变隔离契约。其默认值为 false:在 APISIX 3.18.0 中,这条请求路径上的限流器或 Redis 错误会返回 HTTP 500,而不是绕过限流器。设为 true 时,APISIX 会在不执行该限流器的情况下继续处理请求,因此 Redis 故障可能移除配额保护。配置的 rejected_code: 429 只适用于配额耗尽,并不是 Redis 故障响应。这两条分支由固定版本的 limit-count 源码实现,仍应在目标运行时中实测。

应明确做出选择:

  • false 不会绕过限流;在有文档依据的 APISIX 3.18.0 限流器或依赖错误路径中,请求阶段返回 HTTP 500;
  • true 优先保证请求可用性,但可能让某个租户无限占用共享容量;
  • 两条路径都不能证明租户身份,身份由认证与 Consumer 绑定关系决定;
  • 本地计数器只作用于单个网关实例;Redis 策略跨实例协调计数,但会引入自身的可用性和一致性权衡。

分开权益与运行时计数器

把商业套餐与权益保存在权威控制系统中。将允许的配额策略编译进网关配置,标记版本并审计变更。如果带有明确过期窗口的权益缓存已经足够,就不要在每个请求中调用计费数据库。

计量与执行是两件不同的事。配额计数器决定请求能否继续;使用事件用于分析或计费,可以异步投递。丢失计量事件应触发对账,不应在没有明确设计的情况下悄悄改变运行时执行结果。

规划区域与依赖故障

对每个依赖记录缺失、缓慢、失败和恢复路径:

  • 身份提供商:缓存时长、撤销暴露窗口和缓存过期后的行为;
  • 配额存储:故障放行或故障关闭选择,以及容量保护;
  • 租户目录:陈旧位置的处理方式和迁移窗口;
  • 控制平面:最后一个已知良好配置与恢复流程;
  • 区域 Cell:故障切换资格、数据驻留和状态可用性;
  • 遥测管道:缓冲、采样和敏感数据限制。

当租户数据、密钥、队列或数据驻留规则无法随请求一起迁移时,不要承诺自动区域故障切换。网关只能把流量重定向到能够安全提供服务的后端。

验证清单

  • 公网租户请求头能否覆盖已验证租户映射?
  • 租户 A 的凭证能否访问租户 B 的路由、对象、日志流或计数器?
  • 同一租户中使用不同来源 IP 的已认证 Consumer,是否会共同消耗一个配额窗口?
  • 一个租户的并发或高成本操作是否会拖垮其他租户?
  • 共享计数器存储缺失、缓慢或恢复时会发生什么?
  • 本地和分布式计数器的准确性是否满足业务规则?
  • 策略版本能否先发布到单个 Cell,并在不影响全局的情况下回滚?
  • 日志能否在不把个人或机密数据写入标签的前提下提供有效信息?
  • 平台能否重建事件涉及的身份、策略版本、路由和 Cell?

常见问题

网关添加租户请求头后,它就是安全的吗?

只有在网关先移除或拒绝调用方的值,根据已验证身份生成替代值,并通过调用方无法绕过或冒充的路径发送时,才可以信任。

每个租户都应该使用专属网关吗?

不需要。共享集群或 Cell 通常更高效。只有明确的隔离、网络、容量或合同要求才能证明专属集群合理。

分布式限流能否保证绝对公平?

不能。计数算法、同步、故障行为、重试和请求成本都会影响结果。应把它视为分层设计中的一种准入控制。

后续步骤

先明确分布式限流的准确性与故障权衡,添加并发预算与背压,并建立可审计的访问证据,再接入高影响租户。

获取方案