docs(kvc): freeze reseed slow-path audit + three reviewer challenges
Standalone reference document capturing the v2 reseed slow-path forensic
audit before opening the feat/d-to-p-sync branch. Designed to be quoted
directly by future paper drafts and to prevent the team from re-relitigating
the same questions verbally.
Contents:
§1. The three team-member challenges that disproved "capacity-backup will
save the slow path" (each with code citation and verdict):
1) P pool can't fit all backups -- replay.py:1618-1620 caps backup
count at 1 for sessions with ~50K peak input.
2) P's backup is a stale snapshot -- 49K of direct-to-D append work
never flows through P. _commit_prefill_backup_residency
(replay.py:1483) is only called from seed/reseed paths;
direct-to-D path (replay.py:2719) never touches P-side state.
3) When D evicts, old KV is freed directly (no D->P dump).
session_aware_cache.release_session only calls
kv_pool_allocator.free().
§2. End-to-end reseed timeline (t=0 to t=4550ms) with code citations
showing exactly where each component sits. P-side re-prefill =
1.5-3s, mooncake transfer = 1.5-4s, both contributing 50/50 to
total reseed cost.
§3. Table of "looks like D->P but isn't" code locations -- every
candidate found during forensic search ruled out with line citations.
§4. Specification of what D->P incremental sync would require:
mooncake bidirectional roles (~400 LOC), D-side append commit hook
(easy), P-side radix tree multi-producer extension (the real blocker),
agentic-pd-hybrid replay.py hooks. Estimated 1-2 weeks engineering.
§5. Confirmation via `git ls-remote origin --refs` that author has NOT
secretly implemented D->P on another branch -- only main + this
working branch exist on the server.
§6. Roadmap for the upcoming feat/d-to-p-sync branch.
Appendices: code position crosswalk, related commits, paper section
suggestions.
This document is referenced by V2_DEEP_ANALYSIS_ZH §4.2 and by
KVC_ROUTER_ALGORITHM §9 Open Question 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
368
docs/RESEED_SLOW_PATH_AND_D_TO_P_GAP_ZH.md
Normal file
368
docs/RESEED_SLOW_PATH_AND_D_TO_P_GAP_ZH.md
Normal file
@@ -0,0 +1,368 @@
|
||||
# Reseed 慢路径现状与 D→P KV 同步缺口
|
||||
|
||||
**日期**:2026-05-11
|
||||
**对象**:项目团队 + 后续 paper reviewer
|
||||
**性质**:基线现状落盘 + future-work 缺口定位
|
||||
**前置文档**:
|
||||
- `docs/V2_DEEP_ANALYSIS_ZH.md` §3.2 §4.2(reseed 路径在 v2 数据中的表现)
|
||||
- `docs/KVC_ROUTER_ALGORITHM.md` §3 §9(算法形式化 + open questions)
|
||||
|
||||
**目的**:把"v2 的 reseed slow path 为什么慢、能不能用现有机制治、还差什么"三个问题落盘成单一参考文档,让团队不必再口头反复对齐,让论文 future-work 章节有可引用的基础。
|
||||
|
||||
---
|
||||
|
||||
## 0. TL;DR
|
||||
|
||||
1. KVC v2 在 SWE-Bench 测试中 8.3% 请求走非 direct-to-D 的 reseed/fallback 路径,**单次 reseed 实测 3-7s**(TTFT p99 = 1.28s 全部来自这条路径)。
|
||||
2. 启用真 RDMA(节点有 mlx5_0/_1 @ 200 Gb/s × 2 active)能把 reseed 的 transfer 段(~1.5-4s)压到 ~200-400ms,但**对 re-prefill 段(~1.5-3s)无效**。预期 reseed 总时间从 3-7s 降到 1.7-3.2s,TTFT p99 ~0.7s,**仍输 DP(0.43s)**。
|
||||
3. 真正消除 reseed 长尾必须实现 **D→P 增量 KV 同步**——让 P 端 backup 跟上 D 在 direct-to-D append 路径上累积的 KV,避免 reseed 时重新跑 prefill kernel。
|
||||
4. 经 Opus agent 独立 forensic 审查(commit `9ccd853`)+ 全分支 git 检索:**当前代码、vendored SGLang、mooncake 三层均无 D→P 实现**,作者也没有在其它分支偷偷开发——仓库总共只有 main(旧 baseline)+ kvc-debug-journey-v1-to-v4(本工作分支)两个分支,main 还落后我们 18 个 commit。
|
||||
5. `--kvcache-prefill-backup-policy capacity-backup` 这个 flag 看起来像 D→P 同步但**不是**——它的真实语义只是"reseed 完不关 P streaming session",P 端 KV 仍是 seed-time 的**静态快照**,不随 direct-to-D append 而增长。
|
||||
6. 实现 D→P 增量同步的工程量 ~1-2 周,最难的不是网络层(mooncake 加 D-sender / P-receiver 角色 ~400 LOC),而是 **SGLang radix tree 改成允许从外部 worker 喂数据**——radix cache 当前假设单一生产者。
|
||||
|
||||
---
|
||||
|
||||
## 1. 团队成员的三个质疑(关键框架,paper 引用建议保留原话)
|
||||
|
||||
这三条质疑出自 v2 完成后的对话审查,**直接戳穿了"启用 capacity-backup 就能消除 slow path"的一厢情愿**。每条都有代码层证据支持,**全部成立**。
|
||||
|
||||
### 质疑一:P 节点的 pool 塞得下所有 backup 的 KV cache 吗?
|
||||
|
||||
**回答:塞不下,max 同时 backup ~1-2 个大 session。**
|
||||
|
||||
代码证据(`src/agentic_pd_hybrid/replay.py:1618-1620`):
|
||||
|
||||
```python
|
||||
max_backup_sessions = max(1, capacity_tokens // max(1, target_tokens * 2))
|
||||
max_backup_sessions = min(max_backup_sessions, 4)
|
||||
```
|
||||
|
||||
按 SWE workload 实测代入:
|
||||
- P 池 `capacity_tokens` ≈ 92,104 tokens(SGLang 启动时按 mem_fraction_static 自动分配)
|
||||
- 典型 session peak input `target_tokens` ≈ 50,000-80,000 tokens
|
||||
- 计算:`92K // (50K × 2) = 0` → `max(1, 0) = 1`
|
||||
- → **P 最多同时 backup 1 个大 session**
|
||||
|
||||
对照小 session:
|
||||
- target 20K:`92K // 40K = 2` → backup 上限 2 个
|
||||
- target 10K:`92K // 20K = 4` → backup 上限 4 个(达到代码硬上限)
|
||||
|
||||
→ **capacity-backup 在真实 agentic 长 context workload 下只能救少数 session,不是全员保险。**
|
||||
|
||||
### 质疑二:P 上的 backup 是陈旧快照——49K 的 append 内容根本没经过 P
|
||||
|
||||
**回答:完全正确,这是 capacity-backup 设计上的致命缺陷。**
|
||||
|
||||
**用户提供的反例场景**(已成为 paper 中描述 slow path 的标准例子):
|
||||
|
||||
```
|
||||
turn 0: P 做 prefill 1K tokens → 经 mooncake 传到 D → P 留 1K backup
|
||||
turn 1-50: 全部走 direct-to-D,D 上做 append-prefill,KV 在 D 上从 1K 增长到 50K
|
||||
↑↑↑ 关键:这 49K 的 append 内容(tool 输出、user 消息、模型生成)
|
||||
**从未流经 P 节点**。P 端 backup 锁在 1K 状态。
|
||||
turn 51: D 出于某种原因(容量、迁移、显式驱逐)拒绝 → 触发 reseed
|
||||
→ 即使 P 上有 backup,也只是 turn-0 的 1K
|
||||
→ 实际需要 D 上重建的是 50K(当前完整 context)
|
||||
→ P 必须从 prompt 重新 prefill 49K 的差额
|
||||
→ capacity-backup 节省的 compute 仅 ~2%
|
||||
```
|
||||
|
||||
**代码证据**(独立 Opus agent forensic 审查,commit `9ccd853`):
|
||||
|
||||
1. 唯一更新 `session.prefill_resident_tokens` 的函数是 `_commit_prefill_backup_residency`(`replay.py:1483`)
|
||||
2. 这个函数的唯一 caller 是 `_invoke_kvcache_seeded_router`(`replay.py:2208`)—— 即 seed/reseed 路径
|
||||
3. `_invoke_session_direct`(`replay.py:2719`,direct-to-D 路径)只更新 `session.opened` / `resident_tokens` / `last_trace_request`,**从不触碰任何 P 端字段**
|
||||
4. `_commit_prefill_backup_residency` 内部用 `_estimate_session_resident_tokens(request)` 取的是**完整 request 的预估**,不是 append delta——所以连 bookkeeping 层面都不假设有增量更新
|
||||
|
||||
→ **`capacity-backup` 的真实语义只是"reseed 完之后跳过 `_close_prefill_session`"**(`replay.py:2221`),P 端 streaming session 保持 open 状态、KV 留在 P 的 radix tree 中。但**不存在任何机制让这份 KV 跟上 D 端的 append 增长**。
|
||||
|
||||
### 质疑三:D 触发 reseed 后,本机旧 session 的 KV cache 是不是清空了?P 做完 re-prefill,KV 推到哪里?
|
||||
|
||||
**回答:是的,旧 KV 直接 free 掉;P 重新 prefill 完之后推到 router 选的新 target D(可能同 D,可能换 D)。中间没有"先 dump 到 P 再清"的快捷方式。**
|
||||
|
||||
#### D 端驱逐时的 KV 处理
|
||||
|
||||
代码证据(`replay.py:_close_decode_session`,1539-1569 行;`session_aware_cache.py:release_session`,250-276 行):
|
||||
|
||||
```python
|
||||
# replay.py 端
|
||||
async def _close_decode_session(..., evicting_for_capacity=False):
|
||||
if not session.opened:
|
||||
return
|
||||
await _close_streaming_session(...) # 给 D 发关闭信号
|
||||
# 从 D 的 resident bookkeeping 里删掉这个 session
|
||||
session.opened = False
|
||||
session.resident_tokens = 0
|
||||
if evicting_for_capacity and not session.prefill_opened:
|
||||
residency.decode_evictions_without_prefill_backup += 1
|
||||
|
||||
# SGLang 端(session_aware_cache.py)
|
||||
def release_session(self, session_id):
|
||||
# 解锁引用 + 直接 free KV slots
|
||||
self.token_to_kv_pool_allocator.free(kv_indices)
|
||||
# ↑ 没有序列化、没有外发、没有 D→P 通道
|
||||
```
|
||||
|
||||
**D 驱逐 = 把 KV slot 直接归还给 token pool 分配器。完全没有任何 outbound 网络调用。**
|
||||
|
||||
#### Reseed 时 P→D 的目标选择
|
||||
|
||||
驱逐之后的 reseed 路径(`_invoke_kvcache_seeded_router`,`replay.py:2101`)走的是与 turn 0 完全一样的 P-mediated seeding:
|
||||
|
||||
```
|
||||
1. KvAwarePolicy.select() 选择一个 target D'(可能是同一个 D,也可能因 migration 换 D)
|
||||
2. _invoke_kvcache_seeded_router 在 D' 上 open 一个 streaming session
|
||||
3. 给 P 发完整 prompt → SGLang pd-router 让 P 做完整 prefill
|
||||
4. P 的 prefill 完成后通过 mooncake 把 KV 一次性推到 D'
|
||||
5. D' 上接收完毕,session 重建完成;decode 继续
|
||||
```
|
||||
|
||||
**所以 P 做完 re-prefill 的 KV 推到 KvAwarePolicy 选的 target D'**——可能是:
|
||||
- 同一个 D(驱逐后重新接受)
|
||||
- 另一个 D(如果 reject 计数累积触发 migration,详见 KVC_ROUTER_ALGORITHM §3.3)
|
||||
|
||||
无论哪种,**旧 D 的旧 KV 在新 KV 到达之前就已经被 free**。没有 D→D 的直接迁移路径,没有"先 dump 到 P 再推回"的快捷路径。
|
||||
|
||||
---
|
||||
|
||||
## 2. Reseed 路径的完整 step-by-step 现状
|
||||
|
||||
把上面三个质疑串成端到端流程,以下是 v2 当前 reseed 路径的**完整**操作序列。每一步都标注实测耗时与代码位置。
|
||||
|
||||
### 触发条件
|
||||
|
||||
下列任一发生时 router 走 reseed 路径(详见 `KVC_ROUTER_ALGORITHM.md §3.3`):
|
||||
- D 端 `Admit()` 返回 `can_admit=False`,原因为 `no-d-capacity` / `session-not-resident` / 等
|
||||
- KvAwarePolicy.select 返回的 D 不再持有该 session(migration 触发)
|
||||
- v1/v2 的 reject counter 累积让所有 D 都被 blacklist(极少触发,由 reset-on-success 保护)
|
||||
|
||||
### 端到端时间线
|
||||
|
||||
```
|
||||
t=0 上游 agent 发出 turn N 请求(input ~50K,append ~2K)
|
||||
↓
|
||||
t=~5ms Router 的 KvAwarePolicy.select() 选 target D'(O(|D|) Python 评分)
|
||||
↓
|
||||
t=~10ms Router → D' 发 admit_direct_append RPC
|
||||
↓
|
||||
t=~30ms D' 返回 can_admit=False, reason="session-not-resident"
|
||||
或 "no-d-capacity",Algorithm 3 bump rejects[s, D']++
|
||||
↓ (fallback chain 最多再试 ε-1 个 D,对应 ε ~30ms 总额)
|
||||
t=~100ms 所有 D 都被拒 / 选不到适合 D,路径退化到 seeded router
|
||||
↓
|
||||
t=~110ms Router 转 _invoke_kvcache_seeded_router
|
||||
↓
|
||||
t=~120ms [可选] capacity-backup policy 下:_reserve_prefill_backup_capacity()
|
||||
检查 P 池容量,若不够先 LRU 驱逐别的 P backup session
|
||||
↓
|
||||
t=~150ms P 上 open streaming session(HTTP /session/open)
|
||||
↓
|
||||
t=~200ms 发完整 prompt 到 SGLang pd-router → 路由到 P
|
||||
↓
|
||||
t=~250ms P 开始 prefill
|
||||
↓
|
||||
↓ ←←← 大头 1:P-side re-prefill 段
|
||||
↓ P 必须 prefill 完整 ~50K tokens
|
||||
↓ 即使 capacity-backup 开着,P 的 backup 只有 turn-0 的 ~1K
|
||||
↓ radix prefix cache 命中前 1K,剩余 49K 重算
|
||||
↓ 实测耗时:~1.5-3s @ Qwen3-30B TP1
|
||||
↓
|
||||
t=~2000ms P 完成 prefill,KV 进入 mooncake transfer 队列
|
||||
↓
|
||||
t=~2050ms mooncake 开始 P→D' transfer
|
||||
↓
|
||||
↓ ←←← 大头 2:P→D mooncake transfer 段
|
||||
↓ KV 张量 ~5-9 GB(50K tokens × 2 bytes/token × layers × heads...)
|
||||
↓ **TCP loopback** 实测耗时:~1.5-4s
|
||||
↓ ↑↑↑ 当前 sweep 未启用 RDMA,走的是单机 lo 设备
|
||||
↓ 若启用 IB RDMA @ 200 Gb/s,理论 200-400ms
|
||||
↓
|
||||
t=~4500ms transfer 完成,D' 上 session 重建好
|
||||
↓
|
||||
t=~4510ms D' 开始 decode(小幅度 append-prefill 余下的 ~2K append + 生成)
|
||||
↓
|
||||
t=~4550ms 首个 token 出来 → TTFT 测点
|
||||
```
|
||||
|
||||
**单次 reseed 总耗时:3-7s**(中位 ~2.5s 来自较小 session,p99 ~7.7s 来自最大 session)。**re-prefill 段与 transfer 段大致五五开**,受 session 大小影响。
|
||||
|
||||
### 这就是为什么 v2 的 TTFT p99 = 1.28s
|
||||
|
||||
8.3% slow path 走的是上面这条流水线,其中 reseed 路径(`pd-router-d-session-reseed`)单独占 3.4%(150/4449 请求),构成 KVC TTFT p99 长尾的主要贡献。
|
||||
|
||||
---
|
||||
|
||||
## 3. 已审查的所有"看起来像 D→P 但其实不是"的代码
|
||||
|
||||
下面这些在搜索时容易误判成 D→P 实现,**全部经独立 audit 排除**:
|
||||
|
||||
| 文件:行 | 看起来像 | 实际是 |
|
||||
|---|---|---|
|
||||
| `replay.py:1483 _commit_prefill_backup_residency` | "把 backup 提交到 P" | bookkeeping 函数,更新 `session.prefill_resident_tokens` 计数字段。不传输任何 KV 数据,只在 seed/reseed 完成后被调用。 |
|
||||
| `replay.py:1572 _reserve_prefill_backup_capacity` | "预留 backup 空间" | 检查 P 池可用空间并按 LRU 驱逐别的 backup session 腾位置。不传 KV,只调整 reservation 计数。 |
|
||||
| `cli.py:182 --kvcache-prefill-backup-policy` | "backup 策略" | 只决定 reseed 完成后是否 `_close_prefill_session`。capacity-backup = 保留 P 端 streaming session 不关;release-after-transfer = 立刻关闭。**两种策略下 P 的 KV 都是 seed-time 的静态快照**。 |
|
||||
| `session_aware_cache.py:release_session` | "释放 session(可能含外发)" | 仅调 `kv_pool_allocator.free(kv_indices)`。零网络调用。 |
|
||||
| `disaggregation/decode.py: start_decode_thread` | "decode 端线程,可能有出站" | 纯 receiver loop。处理入站 `AUX_DATA / CHUNK_READY / STAGING_REQ / KVPoll.Success`,**没有出站 KV 传输分支**。 |
|
||||
| `disaggregation/mooncake/conn.py:1563` | "传输请求添加" | `assert disaggregation_mode == PREFILL`——硬约束,只有 P 端能调。 |
|
||||
| `mooncake.MooncakeKVSender` / `MooncakeKVReceiver` | "双向 sender / receiver" | 强角色化:Sender 只在 PREFILL 模式实例化,Receiver 只在 DECODE 模式。`BaseKVManager` 抽象无 bidirectional slot。 |
|
||||
| `pd-router-d-session-reseed-after-eviction` execution_mode | "走 backup 的快路径" | 实际还是走完整 `_invoke_kvcache_seeded_router`(P 完整 prefill + 完整 mooncake transfer),只是 `_eviction_suffix()` 在 execution_mode 字符串末尾加了 "-after-prefill-backed-eviction" 标签。**没有任何 fast-path 优化**。v2 中仅 2/4449 请求走到这个标签。 |
|
||||
|
||||
---
|
||||
|
||||
## 4. D→P 增量同步:要做的是什么
|
||||
|
||||
完整 D→P 增量同步的设计目标:**让 P 端的 backup KV 在 direct-to-D append 完成后异步追上 D 端的 KV,让 reseed 退化为单次 P→D transfer(无需 P re-prefill)**。
|
||||
|
||||
### 抽象数据流
|
||||
|
||||
```
|
||||
当前:
|
||||
direct-to-D append: D 本地 append-prefill,P 端 backup 锁住不变
|
||||
reseed: P re-prefill 完整 50K + P→D transfer 完整 50K
|
||||
|
||||
目标:
|
||||
direct-to-D append: D 本地 append-prefill,**同时**异步把新增的 KV 块推回 P
|
||||
reseed: P→D' transfer 完整 50K (already up-to-date)
|
||||
无需 P re-prefill
|
||||
```
|
||||
|
||||
### 实现层面要改的事
|
||||
|
||||
按工程难度排序:
|
||||
|
||||
#### 4.1 Mooncake 双角色化(中等难度,~400 LOC)
|
||||
|
||||
- `BaseKVSender` / `BaseKVReceiver` 抽象保留,但允许同一 worker 同时实例化两种角色
|
||||
- `MooncakeKVManager.__init__` 把 PREFILL / DECODE 分支改成"role set",允许 worker 同时持有 sender 和 receiver
|
||||
- 新增 `DecodeKVSender` 类(D 端用于把 append KV 推回 P)
|
||||
- 新增 `PrefillKVReceiver` 类(P 端用于接收 D 的 append KV)
|
||||
- 引入第二个 bootstrap channel(避免与原 P→D 通道在 buffer pointer 协商上冲突)
|
||||
|
||||
#### 4.2 D 端 append commit hook(容易)
|
||||
|
||||
- 每次 `direct-to-D-session` 完成后,识别新写入的 KV 块(D scheduler 在 commit 时知道)
|
||||
- 入队 D→P 传输(异步,不阻塞 next request)
|
||||
- 标记 backup 是否成功送达 P(用于后续 reseed 决策)
|
||||
|
||||
#### 4.3 P 端 radix tree 多生产者扩展(**最难,工程量主体**)
|
||||
|
||||
**这是真正的架构 blocker**。SGLang 的 P 端 radix cache 当前假设:
|
||||
- 单一生产者(本 worker 的 model 输出)
|
||||
- 树插入只在 prefill / decode 完成时发生
|
||||
- KV 索引由本 worker 的 token_to_kv_pool_allocator 分配
|
||||
|
||||
要让 P 接收 D 喂来的 KV 块,需要:
|
||||
- 扩展 radix tree 节点的写入路径,允许"外部供给的 KV + token 序列"被插入
|
||||
- 处理 KV 索引重映射(D 的 slot 号在 P 上无意义)
|
||||
- 处理 reference counting(同一 session 可能既被本 worker 用、又被 D 喂回更新)
|
||||
- 处理 eviction policy 协调(P 端 radix LRU 不应让"被 D 喂入的 backup"先被驱逐)
|
||||
- 处理 KV 数据格式的跨 worker 兼容(同样的 model layout,应该是 trivial,但需要测试)
|
||||
|
||||
#### 4.4 agentic-pd-hybrid 端 hook(容易)
|
||||
|
||||
- `_invoke_session_direct` 完成后,新增一步:触发 D→P 同步 RPC(异步)
|
||||
- `_invoke_kvcache_seeded_router` 在 reseed 触发前先 probe P 是否有 up-to-date backup;若有,跳过 re-prefill,只做 P→D transfer
|
||||
- 新增 CLI flag `--enable-d-to-p-sync`,默认 off,保留 baseline 行为
|
||||
- 新增 structural log channel 记录 D→P 同步事件 / 失败 / 延迟
|
||||
|
||||
### 实现完毕后的预期收益
|
||||
|
||||
| 指标 | 当前 (v2) | RDMA only | RDMA + D→P sync |
|
||||
|---|---:|---:|---:|
|
||||
| reseed re-prefill 段 | 1.5-3s | 1.5-3s(不变) | **~0**(已有 up-to-date backup) |
|
||||
| reseed transfer 段 | 1.5-4s | 0.2-0.4s | 0.2-0.4s |
|
||||
| reseed 总耗时 | 3-7s | 1.7-3.4s | **0.2-0.4s** |
|
||||
| TTFT p99 | 1.285s | ~0.7s | **~0.4-0.5s**(与 DP 接近或胜过) |
|
||||
| 8.4% slow path 占比 | 不变 | 不变 | 可能保持但单次代价大幅下降 |
|
||||
|
||||
→ 这就是 paper 里 future-work 应当声明的**"完整版 KVC 才能真正在 TTFT 全分位数上击败 DP"** 的路径。
|
||||
|
||||
---
|
||||
|
||||
## 5. 仓库分支审查(确认无作者私下实现)
|
||||
|
||||
`git ls-remote origin --refs` 完整结果:
|
||||
|
||||
```
|
||||
9ccd853... refs/heads/kvc-debug-journey-v1-to-v4 ← 本工作分支(含本文档)
|
||||
e9062b1... refs/heads/main ← baseline,落后我们 18 commit
|
||||
```
|
||||
|
||||
- **服务器只有 2 个分支**,**0 个 tag**,**0 个隐藏 ref**
|
||||
- main 是更老的 baseline;含 `_commit_prefill_backup_residency` 等同名函数,但语义与本工作分支一致——都是静态 backup,无 D→P 同步
|
||||
- 全 git 历史搜索 `D->P / d-to-p / decode.*prefill.*transfer / kv.*pushback / kv.*sync / incremental / mirror` 关键词,**唯一命中是 commit `9ccd853`**(本文档相关的 doc 改动)
|
||||
- 唯一 remote 是 `origin`(`git@ipads.se.sjtu.edu.cn:wangjh/agentic-pd-hybrid.git`),无 upstream / fork
|
||||
|
||||
→ **作者没有在其它分支偷偷实现 D→P**。这块工作是真空。
|
||||
|
||||
---
|
||||
|
||||
## 6. 下一步
|
||||
|
||||
按 ROI 排序:
|
||||
|
||||
### 必做(落地下一阶段)
|
||||
|
||||
1. **新开 `feat/d-to-p-sync` 分支** 从当前 `kvc-debug-journey-v1-to-v4` 起步
|
||||
2. 写设计文档 `docs/D_TO_P_SYNC_DESIGN_ZH.md`:
|
||||
- 包括上面 §4 的实现细节
|
||||
- 添加 sequence diagram(P/D 通信时序)
|
||||
- 评估 SGLang radix tree 多生产者扩展的具体 API 改动
|
||||
- 评估 D→P 同步对 direct-to-D fast path 自身延迟的影响(理想是异步零开销)
|
||||
3. POC 阶段 1:mooncake 双角色化 + 一个能跑通的 D→P transfer 单测
|
||||
4. POC 阶段 2:P 端 radix tree 多生产者扩展(重点工程量)
|
||||
5. POC 阶段 3:agentic-pd-hybrid 端的 hook + flag
|
||||
6. 端到端验证:跑同 trace 同 ts=1 配置,目标 TTFT p99 < 0.5s
|
||||
|
||||
### 推荐
|
||||
|
||||
7. **同时启用真 RDMA**(独立于 D→P 工作,只需改 sweep 脚本加 `--force-rdma --ib-device mlx5_0`),先把现有 transfer 段加速作为 baseline
|
||||
8. **跑 RDMA-only 对照**:先证明单 RDMA 启用能把 TTFT p99 从 1.28s 压到 ~0.7s,再用 D→P sync 把剩下的 re-prefill 段也吃掉。这样 paper 里能写两条独立的 ablation
|
||||
|
||||
### 不要做的事
|
||||
|
||||
- 在 main / 工作分支上做 D→P 实验(隔离开),主分支应该保持 v2 稳定
|
||||
- 试图通过 capacity-backup 现有 flag "调出"D→P 效果——它结构上做不到
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:本文档涉及的代码位置
|
||||
|
||||
| 函数 / 字段 | 位置 |
|
||||
|---|---|
|
||||
| `_commit_prefill_backup_residency` | `src/agentic_pd_hybrid/replay.py:1483` |
|
||||
| `_reserve_prefill_backup_capacity` | `src/agentic_pd_hybrid/replay.py:1572` |
|
||||
| `_close_prefill_session` | `src/agentic_pd_hybrid/replay.py:1507` |
|
||||
| `_close_decode_session` | `src/agentic_pd_hybrid/replay.py:1539` |
|
||||
| `_invoke_session_direct` (direct-to-D 路径) | `src/agentic_pd_hybrid/replay.py:2719` |
|
||||
| `_invoke_decode_session_direct` | `src/agentic_pd_hybrid/replay.py:2826` |
|
||||
| `_invoke_kvcache_seeded_router` (reseed 路径) | `src/agentic_pd_hybrid/replay.py:2101` |
|
||||
| `DirectSessionState.prefill_resident_tokens` | `src/agentic_pd_hybrid/replay.py:128` |
|
||||
| `_eviction_suffix` | `src/agentic_pd_hybrid/replay.py:1220` |
|
||||
| `--kvcache-prefill-backup-policy` CLI flag | `src/agentic_pd_hybrid/cli.py:182-189, 436-441` |
|
||||
| `MooncakeKVManager.__init__` | `third_party/sglang/python/sglang/srt/disaggregation/mooncake/conn.py:187-256` |
|
||||
| `start_decode_thread` (decode 端 receive loop) | `third_party/sglang/python/sglang/srt/disaggregation/mooncake/conn.py:1425-1496` |
|
||||
| `add_transfer_request` (assert PREFILL) | `third_party/sglang/python/sglang/srt/disaggregation/mooncake/conn.py:1563` |
|
||||
| `MooncakeKVSender` / `MooncakeKVReceiver` | `third_party/sglang/python/sglang/srt/disaggregation/mooncake/conn.py:1648, 1740` |
|
||||
| `BaseKVSender` / `BaseKVReceiver` 抽象 | `third_party/sglang/python/sglang/srt/disaggregation/base/conn.py` |
|
||||
| `session_aware_cache.release_session` | `third_party/sglang/python/sglang/srt/mem_cache/session_aware_cache.py:250-276` |
|
||||
| `session_controller._close` | `third_party/sglang/python/sglang/srt/managers/session_controller.py:293-316` |
|
||||
|
||||
## 附录 B:相关 commit
|
||||
|
||||
| Commit | 内容 |
|
||||
|---|---|
|
||||
| `9ccd853` | docs: D→P 缺口的 Opus forensic audit 写入 V2_DEEP_ANALYSIS §4.2 + KVC_ROUTER_ALGORITHM §9 |
|
||||
| `2ec0deb` | v2 实现(reset-on-success + threshold 2048→8192)—— 直接 trigger 了对 reseed 慢路径的关注 |
|
||||
| `c47adaf` | feat: backpressure pause hint(与 reseed 不直接相关,但展示了"D 端可主动告知 router"的通信通道存在,是未来 D→P sync 控制平面的潜在基础) |
|
||||
|
||||
## 附录 C:相关 paper 章节建议
|
||||
|
||||
- **§Background**:把 §1-§2 的 reseed 现状作为 motivation 摆出
|
||||
- **§Algorithm**:参考 `KVC_ROUTER_ALGORITHM.md` Algorithm 1-3
|
||||
- **§Evaluation §Slow Path Cost**:把 §2 的端到端时间线作为 Figure(sequence diagram)
|
||||
- **§Future Work / Limitations**:把本文 §4 作为 KVC 真正实现"完整 fast path 替代"的 roadmap,引用 D→P 工作的设计文档(后续 `feat/d-to-p-sync` 分支产物)
|
||||
|
||||
---
|
||||
|
||||
**核心句**:v2 实现的 KVC 在 91.6% 请求上证明了 session-affinity 路由的价值,但 8.3% 的 reseed 慢路径让 TTFT p99 比 DP 差 3×。这条慢路径的 50% 时间在 P 端 re-prefill、50% 在 mooncake transfer——RDMA 只能救后者,**D→P 增量 KV 同步是唯一能消除 re-prefill 的机制**,且当前在框架、SGLang、mooncake 三层都没有实现,需要新建 `feat/d-to-p-sync` 分支从设计文档开始。
|
||||
Reference in New Issue
Block a user