Prhub

#45595 [KV Connector][Offloading] Avoid blocking the engine to flush offloads on idle

原始 PR 作者 Etelis 合并时间 2026-06-17 16:35 文件变更 6 提交数 32 评论 18 代码增减 +49 / -81

执行摘要

KV 离负载刷新从阻塞改为非阻塞步进

根据 PR 描述,当所有跟踪请求完成后,OffloadingConnectorScheduler.build_connector_meta 刷新所有在途任务时通过阻塞 worker.wait() 等待完成,该等待运行在引擎核心线程上,导致新到达的请求无法被调度,直到离负载传输全部完成。为避免这种阻塞,需要将空闲时的刷新改为非阻塞排空。

值得精读,特别是对于需要将阻塞操作改为异步非阻塞的场景。该 PR 展示了如何通过一个简单的检查点将引擎步进与传输解耦,同时保持接口一致性。

讨论亮点

Review 中核心讨论集中于方法命名、正确性和设计权衡:

  • 方法命名统一:orozery 建议将 manager 侧方法命名为 has_pending_work 贯穿整个层次结构,以确保一致性。Etelis 采纳。
  • 删除不必要的检查:orozery 指出 tiering manager 的 has_pending_work 不应检查 _pending_load_submissions,因为这些在每步结束时已转为 transfer jobs。Etelis 移除。
  • 避免 fs tier 的 has_pending_work:orozery 认为 fs tier 无需覆盖 has_pending_work,因为若调度器无工作,异步查找结果也不重要。Etelis 移除该覆盖。

实现拆解

  1. 移除阻塞式全部刷新:在 OffloadingConnectorScheduler.build_connector_meta 中,删除了当所有请求完成时立即刷新所有 jobs 的代码块(vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py)。
  2. 添加 has_pending_push_work 检查点:在同一个 scheduler 中新增 has_pending_push_work 方法,返回是否存在未完成的 jobs 或 manager 有 pending 工作。引擎会持续调用直到返回 False。
  3. 暴露到 OffloadingConnector:在 vllm/distributed/kv_transfer/kv_connector/v1/offloading_connector.py 中新增同名方法,委托给 scheduler。
  4. 扩展 tiering manager 接口:在 OffloadingManager 基类(vllm/v1/kv_offload/base.py)和 OffloadingTier 基类(vllm/v1/kv_offload/tiering/base.py)中添加 has_pending_work 默认返回 False。在 TieringManagervllm/v1/kv_offload/tiering/manager.py)中重写该方法,检查内部传输 jobs 和所有二级 tier 的 has_pending_work
  5. 更新测试:在 tests/v1/kv_connector/unit/offloading_connector/test_scheduler.py 中,移除对 expected_flushed 的断言,调整 fence 测试以验证新行为,并新增对 has_pending_push_work 的间接测试。
文件 模块 状态 重要度
vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py 离负载调度器 modified 7.07
vllm/v1/kv_offload/tiering/manager.py 离负载管理层 modified 6.23
vllm/v1/kv_offload/base.py 离负载基础层 modified 5.5
vllm/v1/kv_offload/tiering/base.py 分层基础层 modified 5.5
vllm/distributed/kv_transfer/kv_connector/v1/offloading_connector.py KV 连接器 modified 5.69
tests/v1/kv_connector/unit/offloading_connector/test_scheduler.py 离负载测试 modified 5.91

关键符号

build_connector_meta has_pending_push_work has_pending_work

关键源码片段

vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py core-logic

核心逻辑变更:移除阻塞式全部刷新,添加 has_pending_push_work 检查点。

def build_connector_meta(self, scheduler_output: SchedulerOutput) -> KVConnectorMetadata:
    # ... 前面的处理逻辑保持不变 ...
​
    # [ 关键变更 ] 移除了原先的阻塞式全部刷新逻辑——不再在所有请求完成时
    # 立即等待所有传输完成,而是通过 has_pending_push_work 让引擎继续步进。
    meta = OffloadingConnectorMetadata(
        load_jobs=self._current_batch_load_jobs,
        store_jobs=self._build_store_jobs(scheduler_output),
        jobs_to_flush=self._current_batch_jobs_to_flush,
    )
    self._current_batch_load_jobs = {}
    self._current_batch_jobs_to_flush = set()
    self._current_batch_allocated_block_ids = set()
    return metadef has_pending_push_work(self) -> bool:
    """引擎必须继续步进的检查点。    只要存在未完成的 jobs 或 manager 有未完成的工作,
    即使没有活跃请求,引擎也会持续调用 build_connector_meta 和
    update_connector_output,直到返回 False。
    """
    return bool(self._jobs) or self.manager.has_pending_work()
vllm/v1/kv_offload/tiering/manager.py core-logic

扩展 tiering manager 的 has_pending_work,覆盖基类默认实现,委托到二级 tier。

@override
def has_pending_work(self) -> bool:
    # 检查是否有正在进行的 primary<->secondary 传输(pending promotions
    # 已在 on_schedule_end 中转为 transfer jobs),以及二级 tier 自身的工作。
    return bool(self._transfer_jobs) or any(
        tier.has_pending_work() for tier in self.secondary_tiers
    )

评论区精华

统一命名 has_pending_work 设计

orozery 建议将 manager 侧的方法从 has_pending_push_work 改为 has_pending_work,保持命名一致性。

结论:采用名称 has_pending_work。 · 已解决

去除 _pending_load_submissions 检查 正确性

orozery 指出 tiering manager 的 has_pending_work 不应检查 _pending_load_submissions,因为这些在 on_schedule_end 时已转为 transfer_jobs。

结论:移除对 _pending_load_submissions 的检查。 · 已解决

去除 fs tier 的 has_pending_work 覆盖 设计

orozery 认为 fs tier 无需覆盖 has_pending_work,因为调度器无工作时,异步查找结果不重要。

结论:移除 fs/manager.py 中的 has_pending_work 覆盖。 · 已解决

风险与影响

  1. 回归风险:如果 has_pending_push_work 返回 False 过早,可能导致传输未完成;但内部逻辑确保只要有 jobs 或 manager 返回 True,引擎就会继续步进。
  2. 性能风险:持续步进(keep stepping)可能增加 CPU 开销,但仅在传输活跃时发生,且步进本身并非重计算,开销可控。
  3. 兼容性:只影响 offloading connector 相关的调度路径,不影响其他调度逻辑或模型推理。

对用户:无直接 API 变化,但系统在高负载下的请求响应性得到提升,因为不再因离负载刷新而阻塞新请求。对系统:引擎现在可以在离负载仍有工作时继续步进,确保多级离负载正确排空。对团队:设计的 has_pending_work 接口可扩展,便于未来添加更多异步操作。

核心路径变更 异步设计依赖 测试覆盖调整

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论