第 99 篇
运营 Serverless API:冷启动、幂等性与异步交接
API7.ai
2026年10月29日
API 网关可以认证和限制 Serverless 请求,把它路由到函数或提交服务,并向客户端提供稳定契约。但网关无法消除冷启动,无法让已经超时的函数调用自动变得可安全重放,也不能把队列接受误写成业务工作已经完成。
同步与异步 API 应设计成两种不同的契约。同步调用的截止时间必须覆盖网关处理和函数启动;异步调用则需要持久的操作身份、状态模型、重复处理、保留策略和终态失败路径。
核心要点
- 只有当完整延迟分布都能放进客户端截止时间时,才选择同步执行。
- 如果函数可能已经开始执行,网关超时就应被视为结果未知。
- 幂等性必须落实在应用状态转换中,而不能只依赖网关请求头。
- 只有持久交接完成后才返回
202 Accepted,并提供操作状态契约。 - 分开描述网关准入、云队列接受、函数执行和业务完成。
- 测试冷、热、限流、重复、过期和重放请求。
先选择交互契约
| 契约 | 客户端收到什么 | 适用场景 | 必须设计的主要故障 |
|---|---|---|---|
| 同步 | 最终操作响应 | 工作能够稳定地在总截止时间内完成 | 执行开始后超时 |
| 异步提交 | 操作 ID 和状态位置 | 工作耗时长、突发明显或适合后台重试 | 已接受但稍后失败或过期 |
| 事件摄取 | 事件进入平台的确认 | 生产方不需要与请求关联的结果 | 重复投递与乱序 |
| 回调或 Webhook | 稍后把结果推送给消费者 | 消费者能够认证回调并处理重试 | 伪造、重复或无法送达的回调 |
不要只在长时间同步函数前增加网关超时。这样会同时占用客户端、网关和函数容量,还会让恢复结果更不明确。
分开各个参与者
1flowchart LR
2 C[经过认证的客户端] --> G[API 网关]
3 G -->|短同步请求| F[函数端点]
4 G -->|经过校验的提交| S[提交服务]
5 S -->|持久入队| Q[托管队列或事件服务]
6 Q --> W[函数 Worker]
7 W --> D[幂等状态转换]
8 D --> O[操作状态存储]
9 C -->|轮询操作 ID| G
10 G --> O
11 F -. 执行结果 .-> G
12 Q -. 接受与投递证据 .-> M[运维遥测]
13 W -. 执行与终态结果 .-> M网关负责准入和路由;提交服务负责持久入队和创建操作;队列或云服务决定投递;函数负责执行;应用状态存储决定重复请求是否改变状态。正文、指标和事故响应都应保持这些责任边界。
明确预算冷启动
冷调用可能先经历执行环境分配、运行时初始化、依赖加载、网络设置和应用初始化,然后才进入 Handler。应在接近生产的包大小、内存、网络、区域和依赖条件下测量每个函数版本。
同步路由的预算应满足:
1客户端截止时间 > 网关处理 + 建连 + 平台排队/启动 + 函数执行 + 响应传输 + 恢复余量预置并发可以在 AWS Lambda 收到调用前准备执行环境,但会增加成本,需求超过预置水平时也可能溢出。调用方必须指向拥有预置容量的版本或别名;调用其他版本不会使用该容量池。应把它当作经过度量的延迟与成本选择,而不是“所有请求都热启动”的承诺。
示例:代理有界的函数端点
Apache APISIX 3.19.0 固定版本的 aws-lambda 插件源码通过共享的 generic-upstream 实现调用配置的函数 URL 或 API 端点。下面是一个可运行形态的 Route 请求体;请替换占位 URI,并通过批准的机密路径配置云认证。
1{
2 "uri": "/reports/preview",
3 "plugins": {
4 "aws-lambda": {
5 "function_uri": "https://example-id.lambda-url.us-east-1.on.aws/preview",
6 "timeout": 2500,
7 "max_req_body_size": 1048576,
8 "ssl_verify": true,
9 "keepalive": true,
10 "keepalive_timeout": 60000,
11 "keepalive_pool": 20
12 }
13 }
14}插件会在 max_req_body_size 范围内缓冲请求体;读取请求体失败(包括请求体过大)时返回 HTTP 400。上游请求本身失败时,通用实现返回 HTTP 503。函数返回 400 或更高状态码时,此插件路径会把响应透传,而不会自动重试。
相关行为布尔参数如下:
| 参数 | 默认值 | true 路径 | false 路径与信任边界 |
|---|---|---|---|
ssl_verify | true | 验证 function_uri 的 TLS 服务端证书 | 关闭服务端证书验证;仅有加密不再能证明对端就是预期端点 |
keepalive | true | 复用符合条件的上游连接,并应用连接池和超时设置 | 不复用连接,连接池设置也不生效 |
插件源码还会保留调用方提供的 Authorization 或 x-api-key,而不会用配置的云认证覆盖它。在进入此插件前,应删除或拒绝不可信的客户端云凭证请求头;如果确实要透传,则必须证明这是预期契约。不要让调用方选择 function_uri、区域或云服务。
从 APISIX 视角看,这条代理路径仍然是同步 HTTP。它本身不会创建持久异步操作。
设计持久的异步交接
安全的提交流程如下:
- 认证调用方,并映射到服务端策略;
- 校验负载大小、Schema 和操作类型;
- 要求或生成稳定幂等键;
- 创建带唯一 ID 的操作记录;
- 持久入队,并提交已接受状态;
- 返回带操作 ID 和状态 URL 的
202 Accepted; - 以幂等方式处理消息;
- 写入终态成功或失败;
- 按明确的保留策略清理负载和状态数据。
如果创建操作和发布队列消息无法原子完成,应使用事务性 Outbox 等恢复设计。只启动内存任务后不能返回 202。
响应示例:
1HTTP/1.1 202 Accepted
2Content-Type: application/json
3Location: /operations/op_01JEXAMPLE
4Retry-After: 3
5
6{"operation_id":"op_01JEXAMPLE","status":"accepted"}accepted 表示平台已经在约定的保留和重试契约下持久接受责任,并不表示函数已经运行或业务操作已经成功。
把幂等性做成应用不变量
只有当应用把幂等键绑定到以下信息时,它才有意义:
- 经过认证的调用方或租户;
- 操作类型和规范化请求指纹;
- 已存储结果或终态;
- 保留窗口;
- 同一键携带不同负载时的冲突行为。
网关可以校验幂等键是否存在和格式是否正确,但改变状态的服务必须把该键与业务转换原子绑定。调用方提供的键只是关联值,不是可信身份;必须用认证上下文为它划分命名空间。
重复请求的指纹相同时,应返回原操作或原结果;同一键用于不同工作时则应返回冲突。除了顺序重试,还要测试并发重复。
理解云端重试语义
对于 AWS Lambda Event Function,异步调用会把事件放入队列,并在 Lambda 接受后返回 202。AWS 文档说明,函数错误默认再重试两次;限流和系统错误默认可能在最长六小时内重试。由于队列最终一致,即使函数没有报错也可能重复投递。
这些是 Lambda 服务语义,不是 APISIX 插件的执行模式。应为所选函数配置最大事件年龄、重试次数和失败目标或死信路径。即使减少重试,Handler 仍须保持幂等。
处理同步请求的未知结果
网关超时时,应判断函数是否可能仍在运行或已经提交副作用。如果答案是肯定的,结果就是不明确。没有幂等不变量和状态查询时,不要自动重放支付、消息或资源创建请求。
如果工作流可能比连接存续更久,应尽早返回操作 ID。对于真正同步的操作,要把总重试预算限制在客户端截止时间内,并且只在 HTTP 方法和应用语义允许时重试。
观察每一个阶段
分别跟踪:
- 网关准入、拒绝、超时和上游状态;
- 提交接受与入队延迟;
- 队列年龄、积压、重复投递和过期;
- 冷/热初始化与函数执行时间;
- 并发限流和云厂商错误;
- 幂等命中、冲突和重复抑制;
- 业务成功、失败和不明确状态;
- 回调尝试和最终送达结果。
使用 API、操作类型、函数别名、环境和终态等有界标签。不要把请求 ID、用户 ID 或幂等键放入 Prometheus 标签;在策略允许时把它们放入受访问控制的日志或 Trace。
Serverless API 检查清单
- API 是否明确属于同步、异步、事件或回调模式?
- 同步总截止时间是否包含冷启动和恢复余量?
- 副作用开始后是否可能超时,如何解决结果不明确问题?
- 返回
202 Accepted前是否完成了持久交接? - 幂等键是否按认证身份和请求指纹划分命名空间?
- 是否配置并测试队列重试、重复投递、过期和终态失败?
- 是否记录
ssl_verify与keepalive的默认值和两条路径? - 是否删除不可信的客户端云认证请求头,或明确允许其透传?
- 运维人员能否关联网关、队列、函数和业务结果?
- 回滚是否保留兼容的函数别名、事件 Schema、凭证和状态记录?
常见问题
API 网关能消除 Lambda 冷启动吗?
不能。它可以复用上游连接并路由到已准备的别名,但执行环境就绪状态属于 Serverless 平台和函数配置。
202 Accepted 表示函数已经成功吗?
不表示。它只表示选定的提交边界接受了工作。还需要状态契约和终态失败路径。
只增加幂等请求头就能防止重复副作用吗?
不能。应用必须把幂等键与认证上下文、请求含义和业务状态转换原子绑定。
后续步骤
应用安全的超时与重试策略,设计异步网关模式,并通过网关变更管理交付变更。