Prhub

#29316 [PD] Early-send cached-prefix KV overlapping uncached prefill forward

原始 PR 作者 cctry 合并时间 2026-06-26 04:31 文件变更 3 提交数 2 评论 7 代码增减 +24 / -3

执行摘要

PD 预填提前发送缓存 KV,降低首 Token 延迟

在长共享前缀场景中,传统方式在完整预填前向完成后再发送 KV,传输与计算串行导致 TTFT 偏高。通过将已缓存的设备驻留前缀 KV 提前发送,使传输与后续未缓存后缀计算重叠,可显著降低首 Token 延迟。PR body 指出:'overlapping the transfer with compute to cut TTFT for long shared prefixes'。

建议细致阅读 maybe_send_cached_prefix_chunk 的实现逻辑和 run_batch 中的调用时机。设计上采用非最终 KV 块提前发送以重叠传输与计算,是一种典型的延迟隐藏优化,值得学习。对于使用 PD 分离部署的团队,建议在长前缀场景下验证 TTFT 改善。

讨论亮点

未发现 Review 评论。PR 由作者自行合并,提交历史显示第二提交修复了流水线并行下的 AttributeError 和 mooncake 兼容问题。评论仅包含 CI 触发命令和自动化结果,无人工讨论。

实现拆解

  1. 新增环境变量python/sglang/srt/environ.py):增加 SGLANG_DISAGG_PREFILL_EARLY_SEND_CACHED_PREFIX = EnvBool(True),默认开启,提供关闭开关。
  2. 移动 enable_staging 初始化python/sglang/srt/managers/scheduler.py):在 init_disaggregation 中早期赋值 self.enable_staging,确保流水线并行预填事件循环在 run_batch 调用前即可获取该值,修复第二提交中的 AttributeError
  3. run_batch 前插入提前发送逻辑python/sglang/srt/managers/scheduler.py):在 run_batch 方法中,判断 disaggregation_mode == PREFILL 后,遍历当前批次所有请求并调用 maybe_send_cached_prefix_chunk
  4. 实现核心方法 maybe_send_cached_prefix_chunkpython/sglang/srt/disaggregation/prefill.py):检查条件(环境变量启用、非 staging 模式、请求已完成 bootstrap),计算设备驻留缓存前缀的结束位置 cached_end,若 cached_end > req.start_send_idx 则调用 self.send_kv_chunk(req, last_chunk=False, end_idx=cached_end) 发送非最终 KV 块。
  5. 移除 mooncake 限制python/sglang/srt/disaggregation/prefill.pyprocess_prefill_chunk):去掉 envs.SGLANG_DISAGG_STAGING_BUFFER.get() 的重复设置和 mooncake 相关 gate,因 KV 池在启动时已注册一次。
  6. 移除事件循环中的 staging 赋值python/sglang/srt/disaggregation/prefill.py):event_loop_normal_disagg_prefillevent_loop_overlap_disagg_prefill 中删除 self.enable_staging = ...,避免冗余。
文件 模块 状态 重要度
python/sglang/srt/disaggregation/prefill.py 分离调度 modified 6.8
python/sglang/srt/managers/scheduler.py 调度器 modified 6.01
python/sglang/srt/environ.py 环境配置 modified 4.35

关键符号

maybe_send_cached_prefix_chunk

关键源码片段

python/sglang/srt/disaggregation/prefill.py core-logic

实现核心方法 `maybe_send_cached_prefix_chunk`,控制提前发送逻辑;同时移除事件循环中的 staging 赋值和修复流水线并行兼容性。

def maybe_send_cached_prefix_chunk(self: Scheduler, req: Req) -> None:
    # 仅当环境变量启用、非 staging 模式且请求已完成 bootstrap 时才执行
    if (
        not envs.SGLANG_DISAGG_PREFILL_EARLY_SEND_CACHED_PREFIX.get()
        or self.enable_staging
        or req.pending_bootstrap
    ):
        return
​
    # 计算设备驻留缓存前缀的结束位置(页对齐)
    cached_end = len(req.prefix_indices) - req.host_hit_length
    # 如果没有可提前发送的 KV 块(cached_end <= start_send_idx),则跳过
    if cached_end <= req.start_send_idx:
        return
    # 断言页对齐,确保发送不越界
    assert cached_end % self.token_to_kv_pool_allocator.page_size == 0
    # 发送非最终 KV 块(last_chunk=False),后续还有未缓存后缀的 KV 需要发送
    self.send_kv_chunk(req, last_chunk=False, end_idx=cached_end)

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  • 回归风险:新增 maybe_send_cached_prefix_chunkrun_batch 前无条件触发,若条件判断遗漏(如 staging 模式或 bootstrap 未完成),可能导致异常。但实现有守卫条件(not envs.SGLANG_DISAGG_PREFILL_EARLY_SEND_CACHED_PREFIX.get() or self.enable_staging or req.pending_bootstrap),风险较低。
  • 性能风险:提前发送增加了一次 KV 传输,若共享前缀不长,可能反而增加开销。但默认仅在 cached_end > start_send_idx 时发送,且可通过环境变量关闭。
  • 兼容性:移除了 mooncake 传输后端的 gate,可能影响特定后端的稳定性。但 PR 说明 KV 池启动时已注册,移除后不影响。
  • 流水线并行:第二提交修复了 event_loop_pp_disagg_prefill 中的 AttributeError,但若测试覆盖不足可能遗留问题。未见直接相关测试文件变更。
  • 用户可见:对使用 PD 分离部署且存在长共享前缀的场景,TTFT 预计降低。默认启用,用户无需额外配置;可通过 SGLANG_DISAGG_PREFILL_EARLY_SEND_CACHED_PREFIX=false 关闭。
  • 系统内部:改动集中在预填调度路径,不涉及 decode 端。maybe_send_cached_prefix_chunk 仅在预填节点调用,影响范围有限。
  • 团队协作:变更设计清晰,注释充分,易于理解。缺少测试文件可能增加后续维护风险。
核心路径变更 缺少测试覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论