Files
agentic-kvc/microbench/fresh_setup/PD_DISAGG_INVESTIGATION.md
Gahow Wang b13ca10d19 PD_DISAGG_INVESTIGATION: snapshot Phase 0 done + sweep in flight
Phase 0 infrastructure (vendored proxy, dual-file vLLM patcher,
per-instance + cross-config plotters) is fully assembled and
smoke-validated. Sweep RUN_TAG=20260527_164040 (4 configs × 3 reps
on w600) is running on dash1.

Also realigned the figure list with what `aggregate_mb5.py`
actually produces (mb5_kv_timeline, mb5_peak_utilization,
mb5_latency_compare, mb5_summary.csv).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 00:51:28 +08:00

176 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PD-disagg 在 agentic 下到底为什么不 work — 系统行为级论证
Living TODO 文档。记 H1/H2/H3/H4 四条假设的实验状态,以及每个实验需要的 instrumentation、figures、判定标准。所有 microbench 文件名前缀沿用 `MB`
---
## 当前状态2026-05-27
**问题陈述**:之前关于 "PD-disagg 在 agentic 失败" 的证据只有 colleague 一个数据点TTFT p50 62×、success 52%,在 dash0 patched 栈上。MB1+MB2 算正确账后 phase-isolation 反而 favor PD-disagg**所以我们目前没有 paper-grade 实证证据**。本文档跟踪需要的实验和 system-level 分析。
**核心 gap**:我们只看到 "PD-disagg 表面性能差 10×" 的 headline 数字,但**没有 system-level breakdown 告诉 reviewer "为什么差,差在哪个组件"**。需要的是 D-pool occupancy / scheduler queue depth / KV transfer queue / GPU SM utilization 等系统指标的时间序列,能直接指出 bottleneck。
### Progress2026-05-27 16:50
**Phase 0 done**MB5 pipeline 全部 standing up on dash1 fresh-venv:
- `mb5_launch.sh`8C / 6P+2D / 4P+4D / 2P+6D 单一 launcherstop_all 包含 stale-port 守卫
- `mb5_pd_proxy.py`vendored copy of vLLM 官方 `mooncake_connector_proxy.py`patch 了 `min_tokens` 在 prefill leg 上的兼容性 bug
- `instrument_kv_snapshot.py`patch V1 scheduler 暴露 `schedule()` 结束时的 per-request KV block 分配 + 修复 vLLM 0.18.1 `MooncakeConnectorWorker.bootstrap_server` 在 kv_consumer 模式下未初始化的 AttributeError
- `plot_kv_pool_timeline.py`per-instance KV pool 时间线stacked-area
- `aggregate_mb5.py`:跨 config / 跨 rep 聚合,输出 4 张对比图 + 1 张 CSV
**PD-disagg smoke (4P+4D × 20 reqs)**: 20/20 success, mean latency 3.9s, p99 17s, 8 PIDs 都写 snapshot601 total
对比 8C × 20 reqs 同样数据点会在 sweep 完成后给出。
**Phase 1 在跑**
- RUN_TAG=`20260527_164040`
- CONFIGS=`8C 6P+2D 4P+4D 2P+6D` × REPS=3
- TRACE=`w600_r0.0015_st30.jsonl` (~13 min/rep)
- ETA ~3 h
**Pending**sweep 结果 → 跑 `aggregate_mb5.py` → 写 Phase 2 system analysis。
---
## 4 条独立失败假设
| 假设 | 描述 | 当前证据 | 状态 |
|---|---|---|---|
| **H1** D 池容量天花板 | p99 单请求 11.5 GiB / D-instance 38 GiB pool4P+4D 减半系统 decode 容量;长 context overflow → 排队 | colleague 旧数据 + `f4b` 几何论证 | **need fresh-venv replication + system breakdown** |
| **H2** 静态分池 mismatch | 工作负载 P:D 比例随时间漂移;静态 ratio 无法适应 | 无 | not started |
| **H3** Cache reuse 退化 + P 池 hotspot | round-robin P 丢 affinityAPC 跌sticky P 复现 §3.3 hot pin | 无logical extension | not started |
| **H4** 端到端 throughput 输 | 各 phase 看着 OK 但 wall-clock 输dispatch coupling 放大) | 无 | not started |
---
## Phase 0 — Infrastructure必须先 done
### TODO 0.1: 找 vLLM 标准 PD-disagg 部署方案 ✅ DONE
**结论**:用 vLLM 仓库 ship 的官方 example
`third_party/vllm/examples/online_serving/disaggregated_serving/mooncake_connector/`
- `run_mooncake_connector.sh` —— 参数化 P/D GPU 列表、ports、bootstrap**直接支持任意 P:D 比例**
- `mooncake_connector_proxy.py` —— 官方 FastAPI proxyround-robin P + round-robin Dvendored 到 `microbench/fresh_setup/mb5_pd_proxy.py`,加 `min_tokens=1` 修复
部署形态P 实例用 `kv_role:kv_producer`(带 bootstrap_serverD 实例用 `kv_role:kv_consumer`。后者的 `bootstrap_server` AttributeError 通过 `instrument_kv_snapshot.py` patch 修复。
### TODO 0.2: 包装官方 launcher ✅ DONE
`microbench/fresh_setup/mb5_launch.sh` 单一 launcher支持 `8C / 6P+2D / 4P+4D / 2P+6D`
配套 `mb5_run.sh` orchestratorCONFIG × REP 迭代,含 launch/replay/teardown
### TODO 0.3: System-level instrumentation ✅ DONE (per-request KV)
选了比 `/metrics` 更深的层面:**patch V1 scheduler 直接 dump 每个 `schedule()` 回合的 per-request KV block 分配**10 Hz throttle
- `instrument_kv_snapshot.py` 输出 schema: `{t_unix, step, total_blocks, free_blocks, used_blocks, running:[{req_id, n_blocks, n_computed, n_prompt, n_tokens, status}], waiting:[...]}`
- 每个 EngineCore PID 一份 jsonl集中写入 `MB5_LOG_DIR`
- 跟 prometheus `/metrics` 比:(a) 不需要轮询,(b) 拿到 per-request 而不只是 aggregate(c) 可以反推 D-pool 在某时刻被谁占着
如后续需要 prometheus `/metrics`admission denial 事件之类),可以再加一个 sampler目前的 per-request 数据已经能撑住 Phase 1 + Phase 2 分析。
### TODO 0.4: D 池 occupancy timeline 可视化 ✅ DONE
- `plot_kv_pool_timeline.py` —— per-instance 视图stacked-area: 时间 × 块数 × per-request 色块;底下 waiting queue depth 子图)
- `aggregate_mb5.py` —— 跨 config / 跨 rep 聚合视图cluster-wide KV 时间线、peak 占用率 bar、latency p50/p90/p99 bar、summary CSV
---
## Phase 1 — MB5+3: PD ratio sweep + D-pool occupancy 实测
**Question**: 任何 static P:D ratio 能否打过 8C colo如果不能瓶颈在哪
### 矩阵
```
configs = [8C, 6P+2D, 4P+4D, 2P+6D]
trace = traces/w600_r0.0015_st30.jsonl (1.2k req, ~13 min if not stalled)
reps = 3
```
### Primary metrics (per config, mean of 3 reps)
- [ ] TTFT / TPOT / E2E (mean / p50 / p90 / p99)
- [ ] Success rate
- [ ] **Wall-clock time to drain trace**(→ dispatch coupling amplification
- [ ] APC (effective prefix cache hit ratio)
- [ ] System throughput (req/s steady state)
### System breakdown (the kill-shot evidence)
- [ ] **D-pool occupancy timeline** per D-instance
- [ ] **Scheduler queue depth timeline**waiting requests over time
- [ ] **TTFT per request scatter**colored by which-instance— 看 D 池满了的时候 TTFT 是不是直接挂掉
- [ ] **Admission denial events**(如果 vllm 暴露)
### Output figures (`aggregate_mb5.py` will write all of these)
- [ ] `figs/mb5/mb5_kv_timeline.png` — 4 panels (one per config), cluster-wide KV % 时间线faint per-rep line + bold median
- [ ] `figs/mb5/mb5_peak_utilization.png` — bar chart peak vs steady KV per config含 ±std error bars
- [ ] `figs/mb5/mb5_latency_compare.png` — bar chart p50/p90/p99 e2e latency per config
- [ ] `figs/mb5/mb5_summary.csv` — flat per-(config, rep) 表latency, KV, prefix cache, success rate
- [ ] manual`figs/mb5/mb5_per_instance_timeline.png` — pick 1 rep per config, plot per-instance stacked-area via `plot_kv_pool_timeline.py`,给 paper §3.x system breakdown 用
### 判定标准H1 何时被 confirmed
H1 算 **被证实** 如果同时满足:
1. PD-disagg 在所有非 8C config 上 TTFT p90 ≥ 2× 8C colo
2. D-pool occupancy timeline 显示 D 池 ≥ 90% 持续超过 trace 时长的 30%
3. Scheduler queue depth 在 PD-disagg 下显著高于 8C colo
4. 至少一个 PD config 出现 success rate 下降
H1 算 **被证伪** 如果存在某 PD ratio 使所有指标和 8C colo 差不多 —— 那 §3.2 要重写。
---
## Phase 2 — System analysis钉死 bottleneck
Phase 1 数据出来后,写 system-level analysis
- [ ] 对 4P+4D 配置:哪条 D-instance 哪段时间到 90%?对应那时进来的请求是不是大 KV 的?
- [ ] 比对 8C 和 4P+4D8C 同样时间窗内每个 instance 的 occupancy 是什么样?是不是因为有 prefill workload 帮忙 churn 走?
- [ ] Wall-clock difference attribution用 system metrics 把 PD-disagg 比 8C 慢的 X 秒分解成 (queue_wait + decode + transfer + ...)
- [ ] 看 vllm log 里有没有 "scheduler skipped due to no available KV blocks" 之类事件
预期写一段:
> "在 4P+4D 配置下D 池在 trace 第 X 秒到第 Y 秒持续超过 90% 占用,这段时间 prefill 完成的请求(来自 P 池)平均排队 Z 秒才能进入 decode导致 TTFT p90 从 8C 的 18s 涨到 60s。在 8C 配置下相同时刻 KV 池只到 60%,因为 prefill 完成后 immediately decode 而不需要排队 admission。"
---
## Phase 3 — MB4 cache-reuse × PD-routingsecondary
只在 H1 没被钉死的情况下才优先做;否则当 supporting 实验。
- [ ] 4P+4D 固定,扫 P-routinground-robin / session-sticky / kv-aware
- [ ]APC, P-pool per-worker hotspot, end-to-end TTFT
- [ ] 预期round-robin 丢 ~23pp APCsticky P 池复现 §3.3 hot pin
---
## Phase 4 — 可选 scale-out16 GPU on dash1+dash2
- [ ] Phase 1 结论稳定后才动
- [ ] 配置16C / 8P+8D / 4×(2P+2D)(节点内 disagg + 跨节点协调)
- [ ] 用 cost model如有外推 80 GPU
---
## 时间表(粗估)
- Phase 0infrastructure: 2-3 天 — 调研 vllm 标准部署 + 改 launcher + 加 metrics 采样
- Phase 1MB5+3 sweep: 1 天跑 + 1 天分析 = 2 天
- Phase 2system analysis 写 paper section: 1-2 天
- Phase 3MB4: 2-3 天(可选)
总计:~1 周钉死 H1 + Phase 2 写作。
---
## Notes / open questions
- vLLM 0.18.1 `kv_consumer` mode 的 `bootstrap_server` AttributeError 这次必须正面处理 —— 因为 standard PD-disagg 部署典型用 producer/consumer 角色,不是 kv_both
- D-pool occupancy timeline 是否要补到 MB3 的实验范围里?我倾向 yesPhase 1 自然就 cover
- Cost modeltask #12)是否还需要做?取决于 Phase 1 结论是否需要 analytical 外推