docs: 补充 §7.7 2M 击穿事件 + reserve 改进 + 排障速查更新
- 新增 §7.7: 2M 采集上限击穿事件(20:53 实测)与 reserve 改进 (token_counter + max_tokens + 后置 soft_evict) - §8 排障速查: 补充 2M 击穿(§7.7)、B0 守恒前提(§4.2) - §9 待确认: 新增 reserve 精度验证项,标记 2M 击穿修复完成 - 文件头日期更新
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# 火山免费额度机制速查(VolcEngine Quota Notes)
|
# 火山免费额度机制速查(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 用户确认的业务细则)
|
> - `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 校验限额。
|
直接以网页口径 B0 校验限额。
|
||||||
2. **多包同时过期 > SMALL_BUFFER**:概率低,无法绝对防御。可调大 SMALL_BUFFER 或监控包过期时间。
|
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. 排障速查(今日结论汇总)
|
## 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`、
|
4. 消耗任务 23:00 直连 Ark 绕过 LiteLLM 闸门(防自杀),其自身 clamp:`plan ≤ 2M − usage`、
|
||||||
`plan ≤ 余额快照 − SMALL_BUFFER`,停止条件三闭环
|
`plan ≤ 余额快照 − SMALL_BUFFER`,停止条件三闭环
|
||||||
5. 余额滞后不改变 B0 守恒;30 天过期蒸发是余额下跌的另一来源,
|
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
|
- [~] 余额 API 滞后实测(2026-08-13:Δ≈14 分钟,滞后量 = 窗口内消费,实测 L=149,616 > SMALL_BUFFER
|
||||||
5 万;上限随消费速度变化,建议 SMALL_BUFFER 与消费联动或改用网页 B0 校验,§7.6 遗留风险 1)
|
5 万;上限随消费速度变化,建议 SMALL_BUFFER 与消费联动或改用网页 B0 校验,§7.6 遗留风险 1)
|
||||||
- [x] v4 误拦发现与回退(2026-08-12 15:09 生产日志实证,§7.3)
|
- [x] v4 误拦发现与回退(2026-08-12 15:09 生产日志实证,§7.3)
|
||||||
- [x] v5 废弃(2026-08-12,§7.5;被 v6 Snapshot-Offset 替代)
|
- [x] v5 废弃(2026-08-12,§7.5;被 v6 Snapshot-Offset 替代)
|
||||||
- [x] v6 实施(2026-08-12,§7.6;待生产主机重启生效)
|
- [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,确认与闸门一致)
|
- [ ] 消耗任务口径同步收紧(已改为 vls.SMALL_BUFFER,确认与闸门一致)
|
||||||
- [ ] 空窗期(0:00–返还到账)行为观察:v6 下 B0 自动收紧,确认无异常误杀
|
- [ ] 空窗期(0:00–返还到账)行为观察:v6 下 B0 自动收紧,确认无异常误杀
|
||||||
- [ ] 数据库泄漏:08-12 一天 deepseek-v4 消耗记录量级约 5 万条(此处曾误记「512 亿」,从未烧过该量级,
|
- [ ] 数据库泄漏:08-12 一天 deepseek-v4 消耗记录量级约 5 万条(此处曾误记「512 亿」,从未烧过该量级,
|
||||||
为口径笔误)导致 Redis 内存膨胀;触发监控/清理机制
|
为口径笔误)导致 Redis 内存膨胀;触发监控/清理机制
|
||||||
- [ ] v6 无静态 2M 兜底时的安全:08-13 幸由 B0(2,242,178) > 2M 静态墙兜底;若某日 B0 < 2M,
|
- [ ] v6 无静态 2M 兜底时的安全:08-13 幸由 B0(2,242,178) > 2M 静态墙兜底;若某日 B0 < 2M,
|
||||||
滞后 L > SMALL_BUFFER 时 v6 限额虚高 → 可能放行到余额 0 → 扣费(§7.6 遗留风险 1)
|
滞后 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user