API 网关并发控制通过限制同一时刻正在处理的请求数量来保护上游。合理做法是:根据实测的可持续容量设定限制,只允许少量且有严格时间上限的等待,并在上游陷入延迟和超时的恶性循环之前拒绝多余请求。同时还应配合请求速率限制——速率控制请求进入系统的速度,并发限制则控制被占用的容量。
本文聚焦容量边界本身。关于更广泛的服务等级与目标设计,请参阅 API 网关服务质量;关于准入之后的重试行为,请参阅 API 网关超时与重试。
核心要点
- 每秒请求数和并发量衡量的是不同风险;即使请求速率不高,慢依赖也可能被耗尽。
- 可先根据到达速率和服务时间估算预算,再通过负载测试和生产信号确定真正安全的数值。
- 与其在网关建立无界队列,不如只允许少量有界等待,或尽早拒绝请求。
- 应在最贴近稀缺资源的位置设置限制,例如路由、租户、上游池或高成本操作。
- 调用方触发的策略限制适合返回
429;共享服务容量暂时不可用时适合返回503,同时需要明确重试契约。 - 不要只测试健康状态下的吞吐量,还要测试上游变慢和部分故障。
为什么仅限制请求速率还不够
假设两个端点都以每秒 100 个请求的速度接收流量。其中一个通常在 20 毫秒内完成,另一个需要等待报表数据库两秒。前者平均约有两个请求正在处理,后者则约有 200 个。二者请求速率相同,但对连接、内存、数据库槽位和其他有限资源的需求完全不同。
可使用下面的关系做初步规划:
1平均进行中请求数 ≈ 到达速率 × 平均服务时间系统稳定时,这一关系是 Little's Law(利特尔法则)的一种表达。它只能作为起点,不能直接当作安全配置。尾延迟、突发流量、重试、请求成本差异和下游连接池上限,都会让实际所需余量偏离平均值。
并发控制回答的是“当前允许多少工作占用这个依赖”;速率限制回答的是“允许新工作以多快速度进入”。成熟的准入控制通常两者都需要。
| 控制类型 | 主要边界 | 无法保证的事项 |
|---|---|---|
| 请求速率 | 单位时间内的请求到达量 | 慢请求会快速释放容量 |
| 配额 | 时间窗口内的总用量 | 瞬时负载始终安全 |
| 并发 | 当前正在处理的工作量 | 客户端无法连续发送大量快速请求 |
| 请求大小或成本 | 单次操作使用的资源 | 总到达量或进行中负载保持安全 |
设置数值前先找出容量边界
有意义的并发限制不是“网关最多能接受多少连接”,而是受保护路径在满足延迟与错误目标的前提下,最多能够完成多少已准入工作。
首先找出该路由最先耗尽的资源:
- 上游工作线程或线程槽位;
- 数据库连接或事务争用;
- 连接合作伙伴 API 的套接字;
- 加密、压缩或转换所需的 CPU;
- 大请求和大响应缓冲区所需的内存;
- 具有独立配额的付费下游服务。
然后使用有代表性的载荷进行阶梯式测试。逐步提高并发量,观察吞吐量、排队时间、延迟百分位、错误和资源饱和度。可持续容量通常低于绝对吞吐量峰值:当延迟显著上升而实际完成的吞吐量变化很小时,继续接收工作只是在增加队列。
初始网关预算应低于这一拐点,并为健康检查、运维流量、故障切换和波动保留容量。应用、数据库、实例规格或依赖发生变化后,都应重新测试。从其他路由复制一个数字,并不能证明当前资源可以承受它。
将过量负载转化为明确的背压
当所有准入槽位都被占用时,网关有三种合理选择:
- 短暂延迟。 可以吸收少量调度偏差,但等待必须有严格上限。
- 立即拒绝。 这样可以保留容量,并向调用方提供明确的背压信号。
- 持久接收并稍后处理。 这需要应用层异步契约和持久队列;保持 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-req 和 limit-count,分别用于速率和配额控制。只有在明确每项限制保护哪个边界后才应组合使用;多组任意重叠的限制很难解释和运维。
在故障条件下验证策略
仅在健康状态下得出的限制,在真正需要保护系统时可能并不安全。至少应在预发布环境测试以下场景:
- 提高并发量直到上游接近实测拐点,确认准入控制能够将其保持在所选安全点以内。
- 在不改变到达速率的情况下逐步降低上游处理速度,确认拒绝量上升,而已准入请求的延迟仍然有界。
- 移除部分上游节点,确认预算会缩小,或原有预算已能安全应对容量下降。
- 结合客户端重试策略进行测试,确认重试次数仍然有界。
- 在大量低成本请求中混入一种高成本载荷,检查是否需要独立路由或成本预算。
- 在完整网关集群上测试,识别本地计数器造成的倍增效应。
不要只断言某个峰值 RPS,而应验证真正重要的不变量:最大进行中工作量、最大等待时间、总延迟上限、可接受的完成率,以及负载下降后的恢复能力。
同时监控饱和度和拒绝量
APISIX prometheus 插件会导出网关请求和延迟指标。应将这些指标与上游及依赖遥测关联。实用的仪表盘至少包括:
- 按路由和可信消费者等级统计的准入、延迟和拒绝请求;
- 网关与上游延迟百分位;
- 上游活动请求、工作线程利用率、连接池占用和队列深度;
- 重试次数和请求放大倍数;
- 网关 CPU、内存、活动连接和事件循环健康状况;
- 容量限制调整与部署事件。
拒绝量是保护信号,不能一概视为网关故障。拒绝比例上升、同时已准入请求延迟稳定,可能说明边界正在发挥作用。若拒绝始终为零,但延迟迅速恶化且下游池已满,则可能表示边界不存在或设置过高。
上线检查清单
- 明确稀缺资源及其所有者。
- 使用真实载荷和尾延迟测量可持续运行点。
- 明确预算作用于实例、路由、消费者、上游池还是整个集群。
- 保持等待有界;剩余期限已不足时应尽早拒绝。
- 将并发限制与具有独立依据的到达速率限制配合使用。
- 公开
429、503语义和重试契约。 - 在完整集群上测试慢上游、部分故障与恢复。
- 容量或工作负载发生重大变化后重新校准。
并发控制成功的标准,不是让每个请求都进入队列,而是在过载期间仍能让已准入工作产生有效结果。基于证据设置预算、明确传递背压,并围绕故障开展测试,网关才能成为上游的容量防火墙,而不是另一个积累过载的位置。
总结
API 网关并发控制会在上游仍可保持健康的位置限制进行中的工作量。应根据受保护资源确定预算,只允许有界等待,明确削减多余负载,并在不同租户或路由消耗不同容量时分层设置限制。Apache APISIX limit-conn 可以执行这一边界,速率控制与 Prometheus 遥测则组成完整运维闭环。最终数值必须来自实际工作负载和故障测试。
常见问题
并发限制与速率限制相同吗?
不同。速率限制控制工作进入系统的速度;并发限制控制当前占用容量的工作量。即使请求速率不高,慢请求仍可能耗尽上游。
超额请求应该等待还是立即失败?
只有当队列很小、具有严格边界且仍能满足调用方期限时才应等待。否则应尽早拒绝,向客户端明确传递背压,让已准入工作能够完成。
一个 APISIX limit-conn 数值能保护整个集群吗?
只有当所选策略和键提供所需的共享语义时才可以。使用本地计数器时,每个 APISIX 节点分别执行自己的限制,必须在完整集群上验证总体行为。
下一步
请先查看 APISIX limit-conn 文档,确认当前版本支持的属性,再针对慢上游测试策略。如需围绕 Apache APISIX 集中管理策略并获得企业级支持,可以联系 API7 专家。
