第 96 篇
用 API 网关控制降低云成本:先度量,再优化
API7.ai
2026年10月29日
当 API 网关能够拒绝不该执行的工作、安全复用缓存响应、限制放大效应,并明确哪些路由和消费者正在制造负载时,它可以减少可避免的云成本。但网关无法自动修复低效应用;仅仅增加一层代理不会降低云账单;只看请求数也无法证明真正节省了成本。
应先定义单位经济性和用户可感知的目标。优化的是每次成功业务操作的成本,而不是每个网关请求的成本。如果一种更便宜的路径增加了错误、陈旧数据或事故处置时间,它就不是优化。
核心要点
- 在调整策略前,先用有界的路由或产品维度归因请求、字节、延迟和结果。
- 分开核算网关、网络、计算、托管服务和下游成本,避免一项节省把更大的账单转移到别处。
- 在无效、滥用或超预算流量消耗昂贵的上游资源前将其拒绝。
- 只有在身份、授权、新鲜度和失效边界都明确时才缓存响应。
- 根据实际需求和下游容量扩缩容,不要用增加网关副本代替依赖容量规划。
- 每次只发布一种成本控制,并用可靠性、安全和业务指标作为护栏。
先定义成本单位
实用的成本单位通常是一次成功业务操作,例如已接受的订单、完成的搜索或生成的报告。可以按一个统计周期计算:
1每次成功操作成本 = 可归因的云成本 / 成功业务操作数分子可以包含网关计算、负载均衡、跨可用区或公网传输、可观测性、缓存存储、数据库、队列、函数和第三方调用。分母则不能把业务失败但传输层返回成功的请求算进去。
至少需要跟踪以下维度:
| 维度 | 需要回答的问题 | 常见错误 |
|---|---|---|
| 路由或 API 产品 | 哪个稳定的操作拥有这部分工作? | 把包含 ID 的原始路径作为标签 |
| 消费者类别 | 哪个经过认证的套餐或工作负载类别触发了请求? | 把调用方提供的请求头当成可信身份 |
| 结果 | 操作是成功、被拒绝、被重试,还是结果不明确? | 把每个 2xx 都当成业务成功 |
| 字节 | 有多少数据进入、离开或跨越区域和可用区? | 只看请求数 |
| 依赖 | 调用了哪个上游、队列、函数或供应商? | 把全部下游成本都归到网关 |
| 时间 | 发布、事故或流量迁移是否改变了单位成本? | 比较条件不同的时间窗口 |
Apache APISIX 3.19.0 的 prometheus 插件会暴露请求状态、延迟、带宽和上游相关标签。这些信号可用于归因,但金额仍应以账单为准。需要把网关观测数据与云厂商成本导出和应用业务结果进行核对。
优化前先画出成本路径
1flowchart LR
2 C[经过认证的客户端] --> G[API 网关]
3 G -->|已准入工作| U[上游服务]
4 U --> D[数据库 队列 函数或供应商]
5 G -->|安全缓存命中| R[缓存响应]
6 G -->|无效 滥用或超预算| X[有界拒绝]
7 G -. 请求 字节 延迟 结果 .-> M[成本与可靠性模型]
8 U -. 业务结果 .-> M
9 B[云账单导出] -. 实际支出 .-> M
10 M --> P[经过审查的策略变更]
11 P --> G网关执行经过批准的准入或缓存策略。账单数据只负责报告支出,不负责决定请求授权;应用结果用于证明已接受的工作是否有价值。必须把这些责任分开。
调基础设施前先消除工作量
最便宜的上游调用,是根本不需要发生的调用。建议按以下顺序应用控制:
- 清理废弃客户端、路由、轮询和重复调用;
- 在转发前拒绝格式错误或未授权的请求;
- 限制请求大小、速率、并发、重试和总截止时间;
- 缓存可安全复用的响应;
- 对真正异步的工作进行批处理或交接;
- 最后再为剩余负载调整规格和扩缩容。
不要用限流代替认证或套餐权益判断。计数键必须由服务端根据认证上下文映射。未经验证的 X-Tenant-ID 等请求头会让调用方自行选择另一个租户的预算。
示例:限制并缓存读取路由
下面是一个适用于 APISIX 3.19.0 的可运行形态 Route 请求体。它假设已经存在 catalog-v1 Upstream 和 memory_cache 区域。缓存只保存成功的 GET 和 HEAD 响应 30 秒;生产使用前仍需证明这些响应可安全复用。
1{
2 "uri": "/catalog/*",
3 "plugins": {
4 "limit-count": {
5 "count": 1000,
6 "time_window": 60,
7 "key_type": "constant",
8 "key": "catalog-read",
9 "rejected_code": 429,
10 "allow_degradation": false,
11 "show_limit_quota_header": true
12 },
13 "proxy-cache": {
14 "cache_strategy": "memory",
15 "cache_zone": "memory_cache",
16 "cache_method": ["GET", "HEAD"],
17 "cache_http_status": [200],
18 "cache_ttl": 30,
19 "cache_control": false,
20 "hide_cache_headers": false,
21 "consumer_isolation": true,
22 "cache_set_cookie": false
23 }
24 },
25 "upstream_id": "catalog-v1"
26}设置 cache_control: false 后,内存缓存使用配置的 30 秒 TTL,同时仍会拒绝缓存上游标记为 private、no-store 或 no-cache 的响应。这个常量计数器是路由级容量护栏,不是单用户权益。使用默认本地计数策略时,每个 APISIX 实例维护自己的计数,因此总配额会大致随实例数增长。如果需要整个集群共享一个配额,就必须有意识地设计共享计数策略。
相关行为布尔参数的两条路径如下:
| 参数 | 默认值 | true 路径 | false 路径与信任边界 |
|---|---|---|---|
limit-count.allow_degradation | false | 计数后端失败或动态限制值无效时绕过限流 | 失败返回 500;示例保留此路径,避免控制失效后悄悄放开无界成本 |
limit-count.show_limit_quota_header | true | 返回配额请求头 | 隐藏配额请求头,但不会关闭限流 |
proxy-cache.cache_control | false | 对内存缓存应用请求侧 Cache-Control 语义和 TTL 推导 | 不应用这些请求侧语义;两条路径都会遵守上游的 private、no-store 和 no-cache,不缓存相应响应 |
proxy-cache.hide_cache_headers | false | 对客户端隐藏 Expires 和 Cache-Control | 保留这些响应头 |
proxy-cache.consumer_isolation | true | 按已解析的 APISIX Consumer 或远程用户划分有效缓存键,除非键本身已包含身份 | 在消费者间共享缓存;只有授权和响应内容确实完全相同时才安全 |
proxy-cache.cache_set_cookie | false | 内存缓存可以保存带 Set-Cookie 的响应 | 不缓存这类响应;磁盘缓存不会接受 true 覆盖 |
只有认证链路真正建立了 APISIX Consumer 或远程用户值时,这些值才有意义。缓存不能从任意调用方请求头推断身份。APISIX proxy-cache 文档还说明两种策略都会遵守 Vary;应根据应用契约验证完整缓存键、授权行为和失效路径。
验证缓存是否安全地省钱
衡量缓存命中率时,还要同时观察:
- 减少了多少源站请求和计算时间;
- 增加了多少网关内存或磁盘成本;
- 响应年龄和失效延迟;
- 跨可用区和公网字节;
- 授权与数据隔离测试;
- 陈旧、缺失和错误响应比例;
- p50、p95 和 p99 客户端延迟。
如果缓存键遗漏了语言区域、授权范围、编码或其他表示维度,即使命中率很高也可能不安全。不要为了改善图表而缓存个性化、频繁变更或具有副作用的响应。
控制重试和扇出放大
一个客户端请求可能触发多次网关尝试、服务调用、队列消息、数据库查询和供应商调用。应分别记录客户端请求数和上游尝试数。把总重试预算放在调用方截止时间内,只对已经证明可安全重放的操作重试。
扇出也需要独立预算。一个会调用 20 个服务的搜索接口,成本可能高于 20 个简单接口,尽管网关只看到一个请求。内部工作由应用或编排层负责;网关可以限制输入和时间,却无法推断正确的扇出计划。
约束需求后再调整规格
自动扩缩容是在观察到信号后才调整容量。它不会增加数据库连接、第三方配额或区域网络容量。应使用负载测试得到的容量边界,保留最低热容量,并依据具有前瞻性的需求或饱和度信号扩缩容。
需要测量减少网关副本是否增加了长尾延迟、错误率、连接抖动或事故风险。安全缩容需要排空连接和经过测试的终止预算。具体机制可参考弹性扩展 API 网关。
把成本变更当作实验
每项变更都应记录:
- 假设和预期影响的成本项;
- 受影响的路由与消费者类别;
- 基线周期和比较窗口;
- 可靠性、安全和业务护栏;
- 回滚触发条件与负责人;
- 缓存抖动或数据传输账单等滞后影响;
- 带不确定性的实际单位成本变化。
只有当单位成本确实下降且没有破坏护栏时才推广。供应商折扣、无关流量变化或成功量下降,都可能让总支出降低,却让架构变得更差。
云成本检查清单
- 成本单位是否是一次成功业务操作,而不是一次请求?
- 是否分开核算网关、网络、计算、托管服务和下游成本?
- 每个成本标签是否使用有界且由服务端控制的维度?
- 无效和未授权请求是否在昂贵工作前被拒绝?
- 是否把重试尝试和扇出与客户端请求分开观察?
- 每个缓存键是否包含所有授权与表示维度?
- 是否审查了所有缓存布尔参数、默认值和两条路径?
- 调整规格后,热容量是否仍能承受突发和依赖限制?
- 每项优化是否有可靠性、安全和业务回滚护栏?
- 声称的节省是否与账单导出核对,而非只从流量推断?
常见问题
增加 API 网关会自动降低云成本吗?
不会。网关本身也有计算和运维成本。只有当共享控制减少的浪费或风险超过新增成本时,它才有价值。
所有读取 API 都应该在网关缓存吗?
不应该。只有在新鲜度、身份、授权、缓存键变化、失效和故障行为都明确且经过测试时才缓存。
限流能执行云预算吗?
它可以限制一个已度量的请求维度,但不能代替账单核对、账户级供应商限制或理解业务语义的成本控制。
后续步骤
先在 API 网关定价与成本优化中建立财务模型,再与弹性扩缩容联动,并使用网关日志分析检查路由结果。