一、事故形态
某查询接口向下游渠道商开放三个月后出事:一个大客户的夜间批量任务跑了一整夜,吃光全局共享配额。次日早晨其他五家渠道商的请求全部被拒,错误码统一为限流超限。机器没出任何问题,商务侧五个渠道同时投诉,一家当天提出续约异议。
根因有二:所有调用方共用一个配额桶;超配额后唯一的动作是拒绝。
二、分层设计
| 档位 | 配额策略 | 设计要点 |
| 试用渠道 | 低档位 | 够验证接入即可 |
| 标准渠道 | 日常档位 | 按合同承诺给 |
| 大客户 | 独立桶 + 更高上限 | 独立桶:跑批不挤占他人 |
| 单来源兜底 | 叠加一层 | 单来源过量先被兜住 |
计数按调用方身份而非来源地址;分桶应在开放第一天落地,而非事故后补课。
三、降级返回契约
超配额时查询类接口可给「次优但可用」的答案(缓存快照 / 裁剪字段集 / 受理回执后补)。契约三要素:
- 降级标记:响应体带
degraded: true,不得靠数据新旧暗示; - 降级范围:说明给了什么——缓存快照、精简字段还是异步回执;
- 新鲜度与恢复提示:数据时间戳加重试间隔,调用方据此决策。
def handle_query(channel, params): if quota.allow(channel): return live_query(params) if quota.can_degrade(channel): # 仅查询类 snapshot = cache.get(params.key) if snapshot: return Response( data=snapshot.data, degraded=True, degrade_scope="cached_snapshot", data_time=snapshot.time, retry_after=quota.retry_in(channel), ) return Response(code=429) # 不能降级才硬拒
配合降级数据使用边界说明进文档:哪些场景允许消费、哪些必须等正常档位。
四、验收标准
- 写操作类超配额一律拒绝,无降级分支;
- 降级响应四样齐全(标记、范围、时间戳、重试提示);
- 桶水位八成有预警;
- 降级路径有验收用例:配额调到极小连打三次查询,第三次应得降级数据而非错误码;下单接口同场景应得拒绝。
限流只是上半场,下半场是超了之后给什么。给一份说清范围和新鲜度的次优答案,是开放接口该有的诚意。