# 结构性缺陷验证报告 **日期**:2026-05-06 **对照数据源**: - `outputs/qwen3-30b-tp1-v5-optD-baseline-rerun/`(v5 KVC kv-aware Option D,2P6D,**3 次同配置 rerun**) - `outputs/qwen3-30b-tp1-exps/exp1_8way_dp_cache_aware_summary.json`(同 trace 8DP CA) - `outputs/qwen3-30b-tp1-v5-optD-baseline-rerun/.../logs/decode-{0..5}.log`、`prefill-{0,1}.log` **模型**:Qwen3-30B-A3B(TP1),单机 8×H100 80GB,trace `qwen35-swebench-50sess.jsonl`(4449 reqs / 52 sessions)。 **报告作用域**:验证 `docs/AGENTIC_FIT_ANALYSIS_ZH.md` §1-§7 提出的结构性 claim 是否真实存在;量化影响。 > ⚠️ **环境限制**:本轮缺 GPU 访问,未跑新 sweep。所有数据来自已存在的 v5 rerun + 8DP baseline。Backpressure 代码已实现但**未端到端验证**——下文标注为"预期收益(pending GPU smoke)"。 --- ## 0. 实验有效性锚点:N=1 不可信 3 次 v5 baseline EXP2(**完全相同配置**)的 errors 漂移: | Run | Errors | Lat P50 | Lat P90 | TTFT P50 | |---|---:|---:|---:|---:| | run1 | **372** | 1.11s | 8.65s | 0.147s | | run2 | **912** | 0.94s | 7.68s | 0.071s | | run3 | **396** | 1.22s | 8.43s | 0.183s | errors 漂移 **2.5×**(372 → 912),P50 latency 漂移 **30%**。**任何 N=1 比较 < 30% 差异都不可信。** 后续所有"同 trace 不同配置 / 不同代码"的对比,都需要 N≥3 才有意义。 **对 KVC vs DP 的 headline 数据,3 次 KVC 的最佳值(P50=0.94s)仍然是 DP(P50=0.65s)的 1.45×**——8 way DP 的优势远超 single-run variance 范围,这一头条结论不受 variance 影响。 --- ## §1. Session 永久 pin 到 D + 容量盲选 → 极端双峰 ✅ 完全成立 ### Claim KvAwarePolicy 评分以 hash overlap 为主,没有 D 容量项。Session 第一次落到某 D 后被永久 pin。导致大 session 在已满 D 上反复 admission 拒绝,小 session 在原 D 上 100% 走 direct-to-D。 ### 数据 **(a) Session 永久绑定,跨 3 次 rerun 一致**: ``` run1: 52 sessions, avg distinct-D-per-session = 1.00 run2: 52 sessions, avg distinct-D-per-session = 1.00 run3: 52 sessions, avg distinct-D-per-session = 1.00 ``` 每个 session 在整个运行中只访问 **1 个** D worker,3 次独立 run 完全一致。**不是巧合,是结构。** **(b) Direct-to-D 命中率呈极端双峰**: | Direct-to-D rate | run1 | run2 | run3 | |---|---:|---:|---:| | 0-20%(饿死) | 15 | 18 | 16 | | 20-40% | 7 | 6 | 7 | | 40-60% | 11 | 7 | 9 | | 60-80% | 5 | 6 | 4 | | 80-100%(顺利) | 14 | 15 | 16 | 中间态稀少,两端拥挤。 **(c) 跨 3 次 run 一致饿死的 session 与 session 大小强相关**: ``` 13 sessions starved (<20% direct-to-D) in ALL 3 runs. avg peak input of consistently-starved sessions: 62043 tokens avg peak input of consistently-lucky sessions: 31344 tokens ratio: 1.98× — starved sessions are exactly 2× larger. ``` **13/52 = 25% 的 session 在 3 次独立 run 中都被饿死,且这些 session 的 peak input 恰好是顺利 session 的 2 倍。** 这排除了"运气"假说,证实是大 session 在容量过载 D 上结构性失败。 ### 影响量化 - 25% session 几乎每个 turn 都走 fallback 路径,相对 direct-to-D **TTFT 慢 100×、E2E 慢 6×**(数据点:fallback path mean lat ~3.5s vs direct ~0.5s) - 对应这些 session 的用户体验是"系统性糟糕",而不是"偶尔慢" - **SLO 视角下 P99 完全由这 13 个 session 拉高** ### 结论 **完全成立**。修复方向(不在本轮):policy score 加 capacity penalty + 允许 session 跨 D 迁移,或 D 端引入 hot session retract。 --- ## §2. D 端 LRU 只 evict idle session → 跟不上压力 ✅ 完全成立 ### Claim `scheduler.py:2040` 的 `evict_idle_streaming_sessions_lru` 只能 evict "所有 req 都 finished + streaming 模式"的 session。高并发下 hot session 永远不 idle,LRU 找不到东西可踢。结果 D 顶到 100% 然后撞 mooncake transfer timeout。 ### 数据(v5 baseline rerun run1) | D worker | Trim 事件 | KVTransferError | 峰值 token_usage | |---|---:|---:|---:| | decode-0 | 9 | 0 | 0.99 | | decode-1 | 43 | 4 | 0.99 | | decode-2 | 16 | 153 | 0.97 | | decode-3 | 37 | 29 | 0.99 | | decode-4 | 28 | 90 | **1.00** | | decode-5 | 30 | 93 | **1.00** | **6 个 D 全部峰值 ≥ 0.97**,其中 2 个直接顶到 1.00(KV 池完全耗尽)。**LRU 触发 9-43 次,远不及 transfer 错误的 90-153 次。** decode-2 极端:trim 16 次 vs error 153 次 = LRU 比错误慢 **9.5×**。 ### 影响量化 - 单 run 累计 369 KVTransferError(总 6 个 D 之和) - 对应 ~8% 的请求失败率(v5 errors 9/372/912 三次平均 ~430/4449 = 9.7%) - **每次 mooncake timeout 是 32s**——对 P99 latency 直接贡献几十秒尾巴 ### 结论 **完全成立**。修复方向(不在本轮):分层 eviction——除 idle 外加冷 session retract、按访问频率/时序加权。Backpressure(本轮代码)只是把"D 满"的雪崩从"timeout 错误"转成"主动等待",**不是真正解决容量问题**。 --- ## §3. 没有 D→Replay backpressure 通道 ✅ 成立(已实现修复) ### Claim D 端 transfer queue 堆 → 32s timeout → KVTransferError,没有"D 过载请慢点"信号反向到 replay;concurrency 一直 32 不降。 ### 数据 - §2 的 369 KVTransferError 全部为 32s mooncake timeout(日志中均为 `Failed to send kv chunk` 或 `Decode instance could be dead`) - 错误集中在运行后半段(按现有 `KVC_DEBUG_JOURNEY_V1_TO_V5.md` §v4:错误均在 run 的 44.8% 之后开始累积) - 表明:**前期 D 容量充裕时正常,达到容量上限后所有后续请求集中失败**——典型无 backpressure 系统行为 ### 修复(本轮已实现,待 GPU smoke 验证) 代码改动: 1. `third_party/sglang/python/sglang/srt/managers/io_struct.py`:`DirectAppendAdmissionReqOutput` 增加 `recommended_pause_ms` 字段 2. `third_party/sglang/python/sglang/srt/managers/scheduler.py:admit_direct_append`:基于 `transfer_queue_depth`、`retracted_queue_depth`、`token_usage_after` 计算 hint ```python def _compute_backpressure_pause_hint(...): if retracted_queue_depth > 0: return 1500 if token_usage_after >= 0.90: return max(200, min(2000, overshoot * 5)) if transfer_queue_depth >= 8: return min(2000, transfer_queue_depth * 100) return 0 ``` 3. `src/agentic_pd_hybrid/replay.py`: - `DecodeResidencyState.pause_until_s: dict[str, float]` - `_query_decode_direct_admission` 解析 hint 更新 `pause_until_s` - 新增 `_wait_for_decode_pause`,在 `_invoke_router` / `_invoke_session_direct` 入口检查 4. CLI flag:`--enable-backpressure`、`--backpressure-max-pause-s 2.0`(默认关闭) 5. 结构性日志:`structural/admission-events.jsonl`、`backpressure-events.jsonl`、`session-d-binding.jsonl` ### 预期收益(pending GPU smoke E2 vs E1) - KVTransferError 应从 ~370 / 4449 跌到 < 50 / 4449 - P99 应改善(消除 32s timeout 尾巴) - 整体 latency mean 可能**略升**(被强制 pause),但 P99 应大幅降 - backpressure-events.jsonl 应显示 D-4 / D-5 累积大量 pause 事件(与 §2 数据吻合) ### 结论 **Claim 成立;修复已实现,待 smoke 验证**。注意:backpressure 是**降级**机制,不是性能优化——它把"硬错误"换成"主动等待",整体 throughput 不会因此提升。 --- ## §4. Admission RPC 与 scheduler 主循环耦合 ⚠️ 间接证据,本轮未直接验证 ### Claim `admit_direct_append` 进 scheduler 主循环遍历 session slot,admission RPC 频率 16+/s 时与 decode 抢调度。 ### 现有间接证据 - `docs/V5_PROFILE_INVESTIGATION_ZH.md`:仅加 1Hz `/server_info` polling 就让 EXP2 errors 从 9 涨到 415(46×);但 v6 P0 三次 baseline 不开 polling 同样得到 372/912/396——**polling 不是唯一原因,主循环负载本身就敏感**。 ### 本轮未做 - 没有"admission probe 拆 fast/slow"的对照实验。需要 SGLang 较深的改动(提供 lock-free snapshot),不在 KISS 边界。 ### 结论 **Claim 间接成立,本轮未直接验证**。Backpressure 实现里 admission RPC 的频率没有变(仍每个 turn 一次),只是结果会触发 sleep。如果这条 claim 成立,加 backpressure 后 admission RPC 数量大致不变但每次响应里的 `pause_ms` 会非零——**新增的 admission-events.jsonl 可在 GPU smoke 后用来直接验证此现象**。 --- ## §5. P-side round-robin 不感知 D 健康 ✅ 成立 ### Claim `pd_router.py:_select_decode_index` 是裸 round-robin。任一 P 撞到 hot D 时反复失败,另一 P 完全不受影响。 ### 数据(v5 baseline rerun run1) | Worker | KVTransferError | "Decode could be dead" | |---|---:|---:| | prefill-0 | **367** | 361 | | prefill-1 | **2** | 0 | prefill-0 的请求量从 summary 看是 2225 vs prefill-1 的 2224——**请求量近乎对半,错误率差 180×**。 ### 影响量化 - 失败请求集中在 P-0 → 某个 hot D 的链路上(日志中反复出现 `to 10.45.80.47:XXXXX`) - 单 P 的"死亡链路"贡献了 **99%** 的全部 KVTransferError - 如果 P 选择能避开"正在和 hot D 死磕"的链路,**理论上可消除单 P 故障的雪崩效应** ### 备注 - 此现象**未在 v6 P0 的 3 次 rerun 中横向验证**——只有 run1 的日志可读。需要在新 sweep 的 prefill-{0,1}.log 上重复确认,避免 N=1 嫌疑。 ### 结论 **单 run 数据成立,多 run 一致性未验证**。修复方向(不在本轮):router 选 P 时考虑 (P 当前 inflight transfer 数, 目标 D 健康度)。 --- ## §6. (已撤回)Replay 端 session footprint 估算膨胀 写计划时仔细看代码后撤回——`_estimate_session_resident_tokens` 返回 full prompt,但所有需要"增量"的 call site (`replay.py:1247-1254`、`:1393-1394`、`:1490-1491`) 都已用 `target - current` 减法处理。**不是 bug**。 --- ## §7. time-scale=10 把 inter-turn gap 压到 1/10 ✅ 完全成立 ### 数据 ``` 原始 trace inter-turn gap (n=4397): p10=1.6s p50=2.5s p90=7.8s p99=25.1s max=261s time-scale=10 实际 replay gap: p10=0.16s p50=0.25s p90=0.78s p99=2.5s max=26s ``` 真实 agentic 用户/agent 在 turn 之间停 2-8 秒(思考、打字、tool call、agent reasoning)。time-scale=10 把这些窗口压到 0.16-0.78 秒——**人为消除了 D 的自然 idle 时间**,正好是 KVC 想利用的"session 短暂 idle 时 LRU 可以 evict、其他 session 可以 admit"机会。 ### 测量学影响 - 所有 v3-v6 数据基于 time-scale=10 - 意味着所有"KVC 在 SWE 上输给 baseline"的结论**可能被 benchmark 放大了** - §1 的 25% session 永久饿死现象,在 time-scale=1 下可能因为 D 有更多 drain 时间而显著缓解 ### 本轮未做 - 没跑 time-scale=1 baseline。这是项目当前**最重要但缺失的验证**。 - Smoke sweep 脚本(`scripts/sweep_backpressure_smoke.sh`)E3、E4 包含了 time-scale=1 的 KVC + DP 短 trace 对比,等 GPU 时跑。 ### 结论 **Claim 完全成立;time-scale=1 验证为 P0 待办**。 --- ## 头条对比(同 trace、同硬件) ``` 8-way DP cache-aware (TP1): errors= 0 | latency mean=1.426s p50=0.654s p90=3.609s | TTFT mean=0.123s p50=0.093s p90=0.256s KVC v5 2P6D (3 reruns, no polling): run1: errors=372 | mean=3.50s p50=1.11s p90=8.65s | TTFT mean=2.13s run2: errors=912 | mean=3.00s p50=0.94s p90=7.68s | TTFT mean=1.64s run3: errors=396 | mean=3.42s p50=1.22s p90=8.43s | TTFT mean=2.07s ``` KVC 三次 run 全输 DP,且差距远超 single-run variance: - Latency mean:DP 优 **+110%**(KVC 平均 3.30s vs DP 1.43s) - Latency P50:DP 优 **+65%**(KVC 平均 1.09s vs DP 0.65s) - TTFT mean:DP 优 **+1500%**(KVC 平均 1.95s vs DP 0.12s——慢 17×!) - Errors:DP 0 vs KVC 平均 ~560 **这是这个项目当前最严肃的事实**——所有 KVC 复杂度回报为负。 --- ## 综合结论 按"是否结构性 + 影响大小"的二维分类: | Claim | 结构性 | 影响 | 本轮验证 | 修复(KISS 内) | 修复(KISS 外) | |---|---|---|---|---|---| | §1 Session pin + 容量盲选 | 强 | 大(25% session 饿死) | ✅ 3 run 一致 | ❌ | capacity-aware policy + 跨 D 迁移 | | §2 LRU 跟不上 | 强 | 大(每次 ~370 KVTransferError) | ✅ 6 D 数据 | ❌ | 分层 eviction、hot retract | | §3 无 backpressure | 强 | 中-大(消除 32s timeout 雪崩) | ⚠️ 已实现,待 smoke | ✅ **本轮交付** | – | | §4 admission RPC 干扰 | 弱-中 | 中 | ⚠️ 间接 | ❌ | probe / commit_evict 拆分 | | §5 P-side 不感知 D 健康 | 中 | 中(单 P 错误率差 180×) | ✅ N=1,需 N≥3 复核 | ❌ | router P 选择带 D 健康反馈 | | §6 estimate 膨胀 | – | – | ❌ 已撤回 | – | – | | §7 time-scale=10 失真 | 强(测量学) | 大(可能颠覆所有 KVC vs DP 结论) | ✅ 数据明确 | ✅ 改 flag | – | ### 最关键的两个 takeaway 1. **§7 time-scale=1 是当前项目所有结论的前置依赖**——必须先做。如果 time-scale=1 下 KVC 与 DP 接近,前面所有 v3-v6 的"KVC 输得彻底"诊断都需要重新解读。 2. **§1 + §2 是双胞胎结构性问题**——session 被永久 pin 在某个 D + D 不能 evict 已满 = 大 session 永久卡死。任何不动 policy + 不动 LRU 的修复(包括本轮的 backpressure)只能让症状好看,不能消除根因。 --- ## 本轮代码改动汇总(git diff 范围) ``` src/agentic_pd_hybrid/replay.py # +结构性日志 + backpressure pause 检查 + admission 增强 src/agentic_pd_hybrid/cli.py # +CLI flags src/agentic_pd_hybrid/benchmark.py # +CLI flags 透传 third_party/sglang/python/sglang/srt/managers/io_struct.py third_party/sglang/python/sglang/srt/managers/scheduler.py # +recommended_pause_ms 字段 + hint 计算 scripts/sweep_backpressure_smoke.sh # 4-run smoke sweep(待 GPU 跑) scripts/analysis/analyze_backpressure_smoke.py # 配套分析器 docs/REFACTOR_PLAN_ZH.md # 计划文档 docs/STRUCTURAL_VALIDATION_REPORT_ZH.md # 本报告 ``` 代码默认行为**不变**(`enable_backpressure=False`)——所有现有脚本/配置无影响。 --- ## 待 GPU 时执行 ```bash bash scripts/sweep_backpressure_smoke.sh python3 scripts/analysis/analyze_backpressure_smoke.py outputs/sweep_backpressure_smoke ``` 预算:4 个 run × 30-60 min ≈ 3-4h GPU 时间。 按 §3 的预期:E2 (KVC + backpressure) 相对 E1 (KVC baseline) 应有 errors 降 70%+;P99 改善;TTFT P50 持平或略升。E3 (KVC + backpressure @ time-scale=1) vs E4 (DP @ time-scale=1) 是验证 §7 的关键对照。 如果 E2 vs E1 的 errors 没有显著下降,说明 backpressure hint 公式调得不对(`_compute_backpressure_pause_hint` 阈值可调),或 §3 实际不是雪崩主因(更可能是 §2 D-side LRU 才是)。