一个用户拖垮所有人
多租户系统里最常见的线上事故:某个租户写了脚本猛刷接口,把模型配额、连接数或带宽吃光,
所有租户一起变慢或失败。这类事故靠"事后扩容"救不回来,必须事前隔离。
四层防护
一、配额(Quota)
按租户限定"一段时间内可用多少"(调用次数、token 数、并发数、存储量)。
要点:
- 配额维度要匹配成本来源(对话类按 token,批量任务按条数或并发);
- 超额行为要明确:拒绝、降级到小模型、还是排队等;
- 配额用量对租户可见(避免"莫名其妙失败")。
二、限流(Rate limit)
控制速率(每秒/每分钟),与配额互补:配额防"总量超标",限流防"瞬时打爆"。
- 用令牌桶/漏桶;给突发留一点余量(例如允许 2 倍瞬时);
- 限流键要分层:租户级 + 全局级(全局兜底,防止"每个租户都不超但总量爆");
- 被限流时返回明确状态与建议等待时间。
三、并发隔离
- 每个租户的并发请求数设上限;
- 关键路径与批量任务分池(批量任务不能占满交互请求的池子);
- 队列要有优先级:交互优先、批量让路。
四、降级与熔断
- 上游变慢时,先降级(小模型/缓存/规则兜底),再考虑拒绝;
- 熔断要有恢复探测(半开状态),不要"断了就一直断";
- 每个降级动作都要记录,便于事后归因。
观测什么
- 按租户的用量分布(找出 Top 5 是不是异常增长);
- 拒绝率/限流触发率(被限流的租户是否知道原因);
- 排队时长的 P95(排队比拒绝更容易被忽略);
- 全局与单租户的成本曲线(成本突然抬升往往是脚本或死循环)。
一个可执行的上线清单
- 列出每个接口的成本来源,定配额与限流值(宁可先紧,后放开);
- 加租户级 + 全局级限流;
- 批量与交互分池,队列设优先级;
- 降级链写清楚,熔断加半开探测;
- 把"按租户用量/拒绝率/排队时长"做进看板,并做一次单租户压测验隔离是否真的生效。