API 网关专栏 · 第 48

API 网关并发控制:容量预算、背压与负载削减

2026年09月08日
API 网关并发控制:容量预算、背压与负载削减

API 网关并发控制通过限制同一时刻正在处理的请求数量来保护上游。合理做法是:根据实测的可持续容量设定限制,只允许少量且有严格时间上限的等待,并在上游陷入延迟和超时的恶性循环之前拒绝多余请求。同时还应配合请求速率限制——速率控制请求进入系统的速度,并发限制则控制被占用的容量。

本文聚焦容量边界本身。关于更广泛的服务等级与目标设计,请参阅 API 网关服务质量;关于准入之后的重试行为,请参阅 API 网关超时与重试

核心要点

  • 每秒请求数和并发量衡量的是不同风险;即使请求速率不高,慢依赖也可能被耗尽。
  • 可先根据到达速率和服务时间估算预算,再通过负载测试和生产信号确定真正安全的数值。
  • 与其在网关建立无界队列,不如只允许少量有界等待,或尽早拒绝请求。
  • 应在最贴近稀缺资源的位置设置限制,例如路由、租户、上游池或高成本操作。
  • 调用方触发的策略限制适合返回 429;共享服务容量暂时不可用时适合返回 503,同时需要明确重试契约。
  • 不要只测试健康状态下的吞吐量,还要测试上游变慢和部分故障。

为什么仅限制请求速率还不够

假设两个端点都以每秒 100 个请求的速度接收流量。其中一个通常在 20 毫秒内完成,另一个需要等待报表数据库两秒。前者平均约有两个请求正在处理,后者则约有 200 个。二者请求速率相同,但对连接、内存、数据库槽位和其他有限资源的需求完全不同。

可使用下面的关系做初步规划:

1平均进行中请求数 ≈ 到达速率 × 平均服务时间

系统稳定时,这一关系是 Little's Law(利特尔法则)的一种表达。它只能作为起点,不能直接当作安全配置。尾延迟、突发流量、重试、请求成本差异和下游连接池上限,都会让实际所需余量偏离平均值。

并发控制回答的是“当前允许多少工作占用这个依赖”;速率限制回答的是“允许新工作以多快速度进入”。成熟的准入控制通常两者都需要。

控制类型主要边界无法保证的事项
请求速率单位时间内的请求到达量慢请求会快速释放容量
配额时间窗口内的总用量瞬时负载始终安全
并发当前正在处理的工作量客户端无法连续发送大量快速请求
请求大小或成本单次操作使用的资源总到达量或进行中负载保持安全

设置数值前先找出容量边界

有意义的并发限制不是“网关最多能接受多少连接”,而是受保护路径在满足延迟与错误目标的前提下,最多能够完成多少已准入工作。

首先找出该路由最先耗尽的资源:

  • 上游工作线程或线程槽位;
  • 数据库连接或事务争用;
  • 连接合作伙伴 API 的套接字;
  • 加密、压缩或转换所需的 CPU;
  • 大请求和大响应缓冲区所需的内存;
  • 具有独立配额的付费下游服务。

然后使用有代表性的载荷进行阶梯式测试。逐步提高并发量,观察吞吐量、排队时间、延迟百分位、错误和资源饱和度。可持续容量通常低于绝对吞吐量峰值:当延迟显著上升而实际完成的吞吐量变化很小时,继续接收工作只是在增加队列。

初始网关预算应低于这一拐点,并为健康检查、运维流量、故障切换和波动保留容量。应用、数据库、实例规格或依赖发生变化后,都应重新测试。从其他路由复制一个数字,并不能证明当前资源可以承受它。

将过量负载转化为明确的背压

当所有准入槽位都被占用时,网关有三种合理选择:

  1. 短暂延迟。 可以吸收少量调度偏差,但等待必须有严格上限。
  2. 立即拒绝。 这样可以保留容量,并向调用方提供明确的背压信号。
  3. 持久接收并稍后处理。 这需要应用层异步契约和持久队列;保持 HTTP 请求连接并不等于持久接收。

危险的第四种选择是无界网关队列。它会占用连接和内存、推高尾延迟、导致调用方超时,并可能在原请求仍处于等待时触发重试。Google SRE 的过载处理指南建议:当处理全部请求会威胁服务稳定性时,应执行负载削减(load shedding)。

可以用状态码表达不同边界:

  • 当消费者、凭证或租户超出自身策略时,通常适合返回 429 Too Many Requests。如果服务端能够给出有意义的重试时间,可以附带 Retry-After
  • 当共享服务暂时无法接收更多工作时,503 Service Unavailable 通常更清晰。

状态码本身无法控制客户端如何重试。应公开说明是否允许重试,要求客户端使用退避和抖动,并确保重试仍然经过相同的准入边界。

在多个范围设置预算

单一全局限制可以防止整体崩溃,但仍可能让一个高噪声租户或高成本操作占满全部槽位。只应设置少量且与真实资源对应的分层预算:

1flowchart LR
2    C[客户端] --> G[网关集群安全限制]
3    G --> T[租户或消费者预算]
4    T --> R[路由成本等级]
5    R --> U[上游池容量]
6    U --> D[(数据库或依赖)]
  • 集群或实例安全限制: 防止网关自身耗尽文件描述符、内存或 CPU。
  • 租户预算: 保障公平性,并限制单个客户的突发流量。
  • 路由预算: 区分高成本导出和快速元数据读取。
  • 上游预算: 即使多个路由访问同一上游池,也能保护共享容量。

必须明确计数器作用于单个进程、单个实例还是整个集群。若十个实例分别执行 100 的本地限制,总体准入量可能远高于 100。可以保守地拆分全局预算、在适用时采用受支持的共享计数器,也可以让资源所有者再次执行最终限制。

配置 Apache APISIX limit-conn

Apache APISIX 3.18 提供 limit-conn 插件来限制并发请求。conn 是正常并发阈值;超过该值但仍在 burst 允许范围内的请求会被延迟,超过硬边界的请求则会被拒绝。default_conn_delay 用于控制延迟计算。

以下示例路由用于保护处理缓慢的报表服务。数值仅用于演示,不是生产环境推荐值:

1curl "http://127.0.0.1:9180/apisix/admin/routes/report-export" \
2  -X PUT \
3  -H "X-API-KEY: ${admin_key}" \
4  -d '{
5    "uri": "/reports/export",
6    "methods": ["POST"],
7    "plugins": {
8      "limit-conn": {
9        "conn": 40,
10        "burst": 8,
11        "default_conn_delay": 0.1,
12        "only_use_default_delay": true,
13        "key_type": "var",
14        "key": "server_addr",
15        "rejected_code": 503,
16        "rejected_msg": "Report service is at capacity"
17      },
18      "prometheus": {}
19    },
20    "upstream": {
21      "type": "roundrobin",
22      "nodes": {
23        "reports.internal:8080": 1
24      }
25    }
26  }'

示例中的 server_addr 形成网关服务器范围的键,适合演示实例安全边界,但不能保证集群全局容量。必须根据目标选择键和部署拓扑。若要实现消费者公平性,应先配置身份认证,再使用当前 APISIX 版本支持的、来自可信身份的消费者相关键;不要直接信任客户端提供的租户请求头。

较小的 burst 表示等待余量,并非额外的可持续容量。设置 only_use_default_delay: true 后,被接收的超额请求会按配置延迟。如果等待必然超过调用方期限,应将 burst 设为零并立即拒绝。

APISIX 还提供 limit-reqlimit-count,分别用于速率和配额控制。只有在明确每项限制保护哪个边界后才应组合使用;多组任意重叠的限制很难解释和运维。

在故障条件下验证策略

仅在健康状态下得出的限制,在真正需要保护系统时可能并不安全。至少应在预发布环境测试以下场景:

  1. 提高并发量直到上游接近实测拐点,确认准入控制能够将其保持在所选安全点以内。
  2. 在不改变到达速率的情况下逐步降低上游处理速度,确认拒绝量上升,而已准入请求的延迟仍然有界。
  3. 移除部分上游节点,确认预算会缩小,或原有预算已能安全应对容量下降。
  4. 结合客户端重试策略进行测试,确认重试次数仍然有界。
  5. 在大量低成本请求中混入一种高成本载荷,检查是否需要独立路由或成本预算。
  6. 在完整网关集群上测试,识别本地计数器造成的倍增效应。

不要只断言某个峰值 RPS,而应验证真正重要的不变量:最大进行中工作量、最大等待时间、总延迟上限、可接受的完成率,以及负载下降后的恢复能力。

同时监控饱和度和拒绝量

APISIX prometheus 插件会导出网关请求和延迟指标。应将这些指标与上游及依赖遥测关联。实用的仪表盘至少包括:

  • 按路由和可信消费者等级统计的准入、延迟和拒绝请求;
  • 网关与上游延迟百分位;
  • 上游活动请求、工作线程利用率、连接池占用和队列深度;
  • 重试次数和请求放大倍数;
  • 网关 CPU、内存、活动连接和事件循环健康状况;
  • 容量限制调整与部署事件。

拒绝量是保护信号,不能一概视为网关故障。拒绝比例上升、同时已准入请求延迟稳定,可能说明边界正在发挥作用。若拒绝始终为零,但延迟迅速恶化且下游池已满,则可能表示边界不存在或设置过高。

上线检查清单

  • 明确稀缺资源及其所有者。
  • 使用真实载荷和尾延迟测量可持续运行点。
  • 明确预算作用于实例、路由、消费者、上游池还是整个集群。
  • 保持等待有界;剩余期限已不足时应尽早拒绝。
  • 将并发限制与具有独立依据的到达速率限制配合使用。
  • 公开 429503 语义和重试契约。
  • 在完整集群上测试慢上游、部分故障与恢复。
  • 容量或工作负载发生重大变化后重新校准。

并发控制成功的标准,不是让每个请求都进入队列,而是在过载期间仍能让已准入工作产生有效结果。基于证据设置预算、明确传递背压,并围绕故障开展测试,网关才能成为上游的容量防火墙,而不是另一个积累过载的位置。

总结

API 网关并发控制会在上游仍可保持健康的位置限制进行中的工作量。应根据受保护资源确定预算,只允许有界等待,明确削减多余负载,并在不同租户或路由消耗不同容量时分层设置限制。Apache APISIX limit-conn 可以执行这一边界,速率控制与 Prometheus 遥测则组成完整运维闭环。最终数值必须来自实际工作负载和故障测试。

常见问题

并发限制与速率限制相同吗?

不同。速率限制控制工作进入系统的速度;并发限制控制当前占用容量的工作量。即使请求速率不高,慢请求仍可能耗尽上游。

超额请求应该等待还是立即失败?

只有当队列很小、具有严格边界且仍能满足调用方期限时才应等待。否则应尽早拒绝,向客户端明确传递背压,让已准入工作能够完成。

一个 APISIX limit-conn 数值能保护整个集群吗?

只有当所选策略和键提供所需的共享语义时才可以。使用本地计数器时,每个 APISIX 节点分别执行自己的限制,必须在完整集群上验证总体行为。

下一步

请先查看 APISIX limit-conn 文档,确认当前版本支持的属性,再针对慢上游测试策略。如需围绕 Apache APISIX 集中管理策略并获得企业级支持,可以联系 API7 专家

获取方案