4. Error Budget API 设计原则
Error Budget API 是 SRE 体系中的核心控制面接口,其设计质量直接决定变更窗口的自动化程度与恢复流程的可靠性。本章从 RESTful 规范、幂等性、限流熔断、错误码四个维度展开,确保 API 在生产环境中可运维、可观测、可容错。
4.1 RESTful 设计规范
Error Budget API 遵循资源导向的 RESTful 风格,将 Error Budget 视为一级资源,通过标准 HTTP 动词表达操作意图。
| HTTP 方法 | 资源路径 | 语义 | 幂等 |
|---|---|---|---|
| GET | /api/v1/budgets/{service} | 查询指定服务的 Error Budget 余额 | 是 |
| POST | /api/v1/budgets/{service}/consume | 消耗预算(触发变更窗口) | 否(需幂等令牌) |
| POST | /api/v1/budgets/{service}/restore | 恢复预算(回滚/补偿) | 否(需幂等令牌) |
| GET | /api/v1/budgets/{service}/history | 获取预算变更历史 | 是 |
命名规范:资源路径使用复数名词(budgets),服务名作为路径参数,动词通过 HTTP 方法表达。避免在路径中使用动词如 /consumeBudget,而是用 POST + 子资源 /consume。
4.2 幂等性设计
在变更窗口和备份恢复场景中,网络重试可能导致预算重复消耗或重复恢复。幂等性设计是防止状态不一致的关键防线。
- 幂等令牌(Idempotency-Key):客户端在 POST 请求头中携带全局唯一令牌,服务端缓存该令牌的处理结果。重复请求直接返回缓存结果,不执行实际逻辑。
- 条件更新(Optimistic Locking):使用版本号或时间戳字段,更新时校验当前版本与请求版本一致,避免并发覆盖。
- 天然幂等操作:GET、PUT、DELETE 方法本身幂等;POST 必须配合幂等令牌或业务唯一键。
// 幂等令牌校验伪代码
POST /api/v1/budgets/gateway/consume
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
// 服务端处理逻辑
if cache.exists(idempotencyKey):
return cache.get(idempotencyKey)
else:
result = consumeBudget(service, amount)
cache.set(idempotencyKey, result, ttl=3600)
return result
避坑:幂等令牌的 TTL 必须大于客户端最大重试超时时间。建议设置为 1 小时,并在响应头中返回 Idempotency-Key-Expires 字段,方便客户端判断。
4.3 限流与熔断
Error Budget API 是变更窗口的入口,一旦被突发流量打满,可能导致整个变更流程失控。限流和熔断是保护 API 自身稳定性的核心手段。
4.3.1 限流策略
| 维度 | 限流粒度 | 阈值示例 | 响应方式 |
|---|---|---|---|
| 全局 | 所有服务共享 | 1000 req/s | 429 Too Many Requests |
| 服务级 | 按 service 路径参数 | 100 req/s | 429 + Retry-After |
| 用户级 | 按 或 | 20 req/s | 429 + X-RateLimit-Reset |
4.3.2 熔断机制
当后端存储(如 Redis/MySQL)或下游依赖出现连续错误时,熔断器自动打开,快速失败而非等待超时。
- 关闭状态:正常处理请求,统计错误率。
- 打开状态:错误率超过阈值(如 50%),直接拒绝请求,返回 503 Service Unavailable。
- 半开状态:经过冷却时间(如 30s),允许少量探测请求,成功则关闭熔断器,失败则重新打开。
最佳实践:限流和熔断的阈值应与 Error Budget 消耗速率联动。当 Budget 剩余不足 10% 时,自动降低限流阈值并缩短熔断冷却时间,优先保护剩余预算不被异常流量耗尽。
4.4 错误码定义
统一的错误码体系让客户端能够精确判断错误类型并采取对应策略。Error Budget API 采用三段式错误码:HTTP 状态码 + 业务码 + 描述信息。
| HTTP 状态码 | 业务码 | 描述 | 客户端处理建议 |
|---|---|---|---|
| 400 | EB_BAD_REQUEST | 请求参数校验失败 | 检查请求体字段 |
| 401 | EB_UNAUTHORIZED | 认证失败或 无效 | 刷新令牌 |
| 403 | EB_FORBIDDEN | 无权限操作该服务的 Budget | 联系管理员授权 |
| 404 | EB_SERVICE_NOT_FOUND | 指定的服务未注册 | 检查服务名 |
| 409 | EB_CONFLICT | 版本冲突或预算状态异常 | 重新获取最新状态后重试 |
| 429 | EB_RATE_LIMITED | 请求频率超限 | 等待 Retry-After 后重试 |
| 503 | EB_SERVICE_UNAVAILABLE | 熔断器打开或后端不可用 | 指数退避重试 |
// 错误响应体 JSON 格式
{
"error": {
"code": "EB_RATE_LIMITED",
"message": "请求频率超过服务级限流阈值",
"details": {
"limit": 100,
"current": 101,
"reset_at": "2025-03-15T10:00:00Z"
},
"request_id": "req-abc123"
}
}
设计要点:
- 每个错误响应必须包含 request_id,便于链路追踪。
- 429 和 503 错误必须附带 Retry-After 或 reset_at 字段,指导客户端重试时机。
- 业务码使用大写字母 + 下划线,前缀 EB_ 标识 Error Budget 域。
4.5 综合架构示意
下图展示 Error Budget API 在变更窗口场景中的完整调用链路,涵盖限流、幂等校验、熔断和错误码返回。
实战要点:在变更窗口的 consume 和 restore 接口中,幂等校验应优先于限流执行,避免因限流丢弃幂等重试导致客户端误判。熔断器打开时,限流层应直接返回 503,不再消耗令牌。