From 65c52442c85854c2cb9c15a20fc8f7397201100b Mon Sep 17 00:00:00 2001 From: vibe-code Date: Thu, 13 Aug 2026 04:16:52 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=20=C2=A77.7=202M=20?= =?UTF-8?q?=E5=87=BB=E7=A9=BF=E4=BA=8B=E4=BB=B6=20+=20reserve=20=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=20+=20=E6=8E=92=E9=9A=9C=E9=80=9F=E6=9F=A5=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 §7.7: 2M 采集上限击穿事件(20:53 实测)与 reserve 改进 (token_counter + max_tokens + 后置 soft_evict) - §8 排障速查: 补充 2M 击穿(§7.7)、B0 守恒前提(§4.2) - §9 待确认: 新增 reserve 精度验证项,标记 2M 击穿修复完成 - 文件头日期更新 --- docs/volc-quota-notes.md | 102 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/docs/volc-quota-notes.md b/docs/volc-quota-notes.md index daffeff..8fb9c08 100644 --- a/docs/volc-quota-notes.md +++ b/docs/volc-quota-notes.md @@ -1,6 +1,6 @@ # 火山免费额度机制速查(VolcEngine Quota Notes) -> 日期:2026-08-12(2026-08-13 增补:网页口径校准 + v6 滞后击穿实测,§4.2/§7.6) +> 日期:2026-08-12(2026-08-13 增补:网页口径校准 + v6 滞后击穿实测 §4.2/§7.6 + 2M 击穿事件 §7.7) > 用途:后续限额/防扣费设计、排障、消耗任务的事实基础,避免重复推导 > 来源: > - `merge-auto-consume.md` §1(2026-08-11 用户确认的业务细则) @@ -302,6 +302,90 @@ limit = balance_at_sync + usage_at_sync - SMALL_BUFFER(5k) = B0 + L - SMALL_BUFF 直接以网页口径 B0 校验限额。 2. **多包同时过期 > SMALL_BUFFER**:概率低,无法绝对防御。可调大 SMALL_BUFFER 或监控包过期时间。 + +### 7.7 2M 采集上限击穿事件与 reserve 改进(2026-08-12 20:53 实测) + +#### 事件回顾 + +``` +20:38:26 Today: 1,696,233 (delta +98) +20:53:13 Today: 1,872,804 (delta +176,571) ← 单请求消耗 176k +20:53:18 突发触发 (+176,669 > 100,000) +20:53:35 同步完成: Usage=2,050,826 ← 已超 2M! +23:18:59 下次同步: Bal=242,178 (API 滞后修正,B0 回归 2,293,004) +火山网页: 今日采集量 2,000,000/2,000,000 ← 2M 撑满 +``` + +**2M 采集上限确实撞了**,usage 超出 50,826 token。但 B0=2,293,004 > usage,未扣费。 + +#### 根因:reserve 估算不足 + 并发击穿 + +旧 reserve 逻辑: +```python +reserve = data.get("max_tokens") or PREBLOCK_RESERVE_TOKENS(50000) +# 闸门: usage + reserve >= effective_limit → 429 +``` + +deepseek-v4-flash 单请求实际消耗 176,571 token(远超 reserve 50k): +``` +请求放行时: usage=1,800,000, reserve=50,000 → 1,850,000 < 2M → PASS +请求完成后: usage=1,976,571 (单请求吃了 176k) +下一个请求: usage=1,976,571, reserve=50,000 → 2,026,571 >= 2M → BLOCK +# 但此时已经超了 2M +``` + +**并发请求放大问题**:多个请求同时通过闸门(都读到 usage < 2M),各自实际消耗叠加, +放行时 usage 相加不超限,完成后集体超限。 + +#### B0 守恒假设的再次验证 + +``` +20:33 B0 = 596,869 + 1,696,135 = 2,293,004 +20:53 B0 = 596,771 + 2,050,826 = 2,647,597 ← 虚高(API 未结算 17.6 万消耗) +23:18 B0 = 242,178 + 2,050,826 = 2,293,004 ← API 修正后回归初值 +``` + +B0 守恒 **在 API 滞后收敛后成立**,但同步快照期间虚高(§4.2 的 L 量)。 + +#### reserve 改进:token_counter 精确估算输入 + +```python +# 旧:盲猜 +reserve = data.get("max_tokens") or 50000 + +# 新:精确输入 + 声明输出 +input_tokens = litellm.token_counter(model=data["model"], messages=data["messages"]) +# 未知模型 fallback cl100k_base,对中文偏高(更安全) +max_out = data.get("max_tokens") or PREBLOCK_RESERVE_TOKENS +reserve = input_tokens + max_out +``` + +**为什么中文偏高更安全**:DeepSeek 自有 tokenizer 对中文 ~1.5 token/字, +cl100k_base ~2-3 token/字。估算偏高 = 预留更多 = 提前撞线 = 更保守。 + +**效果**:输入 200k 的请求,旧 reserve 只有 50k,新 reserve 250k+, +在 usage=1.8M 时就拦住(而非放行后超 2M)。 + +#### 后置闸门兜底 + +```python +# _record_usage 里,写完 usage 后: +if current_total >= effective_limit: + soft_evict_from_router(raw_model, api_base) # 改名踢出,后续全 429 +``` + +前置闸门挡不住已放行的请求,但 `_record_usage` 完成记账后检查超限, +立即 `soft_evict`,后续请求全部 429。 + +#### 双重防线总结 + +| 防线 | 机制 | 挡什么 | 挡不住什么 | +|---|---|---|---| +| **前置** | `reserve = token_counter(messages) + max_tokens` | 预估超限的请求 | 实际消耗 > reserve 的请求 | +| **后置** | `current_total >= effective_limit → soft_evict` | 超限后的后续请求 | 已发出正在执行的请求 | + +**遗留**:若 `max_tokens` 未声明且模型输出无上限,前置仍可能预估过低。 +此时只有后置 `soft_evict` 兜底(挡后续不挡本次)。 --- ## 8. 排障速查(今日结论汇总) @@ -314,16 +398,28 @@ limit = balance_at_sync + usage_at_sync - SMALL_BUFFER(5k) = B0 + L - SMALL_BUFF 4. 消耗任务 23:00 直连 Ark 绕过 LiteLLM 闸门(防自杀),其自身 clamp:`plan ≤ 2M − usage`、 `plan ≤ 余额快照 − SMALL_BUFFER`,停止条件三闭环 5. 余额滞后不改变 B0 守恒;30 天过期蒸发是余额下跌的另一来源, - 与消耗扣减区分(如 08-12 余额 1,558,307 → 596,869,其中约 50 万为滞后修正 + 过期)## 9. 待确认/风险清单 + 与消耗扣减区分(如 08-12 余额 1,558,307 → 596,869,其中约 50 万为滞后修正 + 过期) +6. 2M 采集上限可被单请求 + 并发击穿(§7.7):reserve 估算不足时已放行的请求继续消耗, + `soft_evict` 后置兜底只能挡后续。修复:reserve = `litellm.token_counter(messages)` + `max_tokens` +7. B0 守恒仅在 API 滞后收敛后成立;同步快照期间 `balance + usage = B0 + L`(虚高,§4.2), + 不是真实 B0。判扣费用网页真实初始余额或收敛时点反推 + +--- + +## 9. 待确认/风险清单 - [~] 余额 API 滞后实测(2026-08-13:Δ≈14 分钟,滞后量 = 窗口内消费,实测 L=149,616 > SMALL_BUFFER 5 万;上限随消费速度变化,建议 SMALL_BUFFER 与消费联动或改用网页 B0 校验,§7.6 遗留风险 1) - [x] v4 误拦发现与回退(2026-08-12 15:09 生产日志实证,§7.3) - [x] v5 废弃(2026-08-12,§7.5;被 v6 Snapshot-Offset 替代) - [x] v6 实施(2026-08-12,§7.6;待生产主机重启生效) +- [x] 2M 采集上限击穿修复(2026-08-12 20:53 实测 §7.7:reserve 改用 token_counter + max_tokens, + 后置 soft_evict 兜底;23:18 重启后 PRE-BLOCK 生效) - [ ] 消耗任务口径同步收紧(已改为 vls.SMALL_BUFFER,确认与闸门一致) - [ ] 空窗期(0:00–返还到账)行为观察:v6 下 B0 自动收紧,确认无异常误杀 - [ ] 数据库泄漏:08-12 一天 deepseek-v4 消耗记录量级约 5 万条(此处曾误记「512 亿」,从未烧过该量级, 为口径笔误)导致 Redis 内存膨胀;触发监控/清理机制 - [ ] v6 无静态 2M 兜底时的安全:08-13 幸由 B0(2,242,178) > 2M 静态墙兜底;若某日 B0 < 2M, - 滞后 L > SMALL_BUFFER 时 v6 限额虚高 → 可能放行到余额 0 → 扣费(§7.6 遗留风险 1) \ No newline at end of file + 滞后 L > SMALL_BUFFER 时 v6 限额虚高 → 可能放行到余额 0 → 扣费(§7.6 遗留风险 1) +- [ ] reserve 精度验证:token_counter fallback cl100k_base 对中文偏高,需实测确认偏差范围 + (DeepSeek 自有 tokenizer ~1.5 token/字 vs cl100k_base ~2-3 token/字,§7.7)