mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-10-05 15:07:51 +00:00
复查后修掉一个自己引入的缺陷,并补上此前缺失的交叉场景验证。 ## 修复:拒绝路径重复判定 4 个入口原本先 checkModelScope(判是否为空)再 writeScopeReject (内部又 checkQuota 一次)。即每个【被拒】的请求要跑两遍配额统计, 且两次之间用量可能变化 —— 判定与响应存在理论竞态。 改为 checkQuota 一次判定直接把 *quotaRejection 交给 writeReject, 消息与 Retry-After 都来自同一次读,不再有二次求值。 checkModelScope 保留(只需知道放行与否的调用方仍可用)。 ## 补判据:此前完全没验证过的交叉场景 1. TestKeyQuotaWinsOverSlotQuota —— key 配额与 AUTO 槽位配额是两种 不同作用域的限额(槽位是全网关共享的上游预算,key 配额属于单个 调用方)。两者同时耗尽时必须报【key 配额】:报槽位配额会被表述成 「无可用容量」,读起来像上游故障,而调用方能处理的恰恰是 key 配额。 2. TestUncappedKeyNeverBlockedByEmptyScope —— 只配模型范围、不配配额的 key(生产上 5 把 user key 全是这种)绝不能被槽位检查误伤。 ## 复查补测的实测数据 配额检查的真实开销(每请求一次,走完整 checkQuota 路径): 配了配额 149 ns 0 allocs 未配配额 42.6 ns 0 allocs <- 生产上 5/7 把 key 是这种 admin key 37 ns 0 allocs 未配配额的 key 只付 FindKey 的开销、根本不碰桶。相对一次 LLM 请求 (秒级)可忽略。 生产配置副本(7 key / 16 源 / 真加密凭据 / 真上游)实测: - 100 并发 -> 50 成功 / 50 容量拒绝,RSS 19.9 -> 25.8 MB - 生产形态桶内存(7 key x 8 model x 2 源 x 40 天满 retention) = 3.73 MB,占 ~32MB 预算的 11% - 配额记账与 stats 一致:配 63000 配额后报 64062/63000 - **跨重启存活**:重启后从审计日志回放,仍报 64062/63000 并拦截; 未配配额的 key 仍 200