Prhub

#38096 [Core][KV Connector] Remove use of num_cached_tokens in error handling

原始 PR 作者 markmc 合并时间 2026-03-26 02:20 文件变更 1 提交数 1 评论 7 代码增减 +17 / -12

执行摘要

重构 KV 缓存失效处理逻辑,移除了对 num_cached_tokens 的依赖,统一同步与异步加载场景下的令牌计数计算。

PR body 中明确指出,目标是“重构 _update_requests_with_invalid_blocks() 以避免基于 num_cached_tokens 的重计算逻辑,简化逻辑,并使同步共享块的情况不那么特殊”。此外,这也为“重构预填充缓存统计以消除 Counters can only be incremented by non-negative amounts 报告” (#37460) 以及基于 Or 在 #35223 中的工作奠定了基础。

对于负责调度器、KV 缓存管理或 KV 连接器模块的工程师,建议快速浏览此 PR 以理解错误处理逻辑的简化方向。重点关注 req_num_computed_tokens 的新计算方式及其背后的设计意图(精确反映已计算且已缓存的令牌)。对于更广泛的团队,可以将其视为一个代码清理和统一接口的示例。

讨论亮点
  1. 性能优化讨论:gemini-code-assist[bot] 在 review 评论中指出,对于新分配但尚未使用(即“空”)的无效块,将其加入 blocks_to_evict 进行驱逐可能带来不必要的开销,建议直接调用 kv_cache_manager.free()。但作者 markmc 回应认为,在“不同步传输且不重新计算”的场景下,仍需要驱逐所有后续块(包括新调度的令牌对应的块),并最终确认当前(及修改后)的代码行为(驱逐所有后续块)是“好的”。
  2. 实现简化建议:在 Issue 评论中,审阅者 orozery 提出,此变更看起来比实际需要的更大,并建议一种更直接的替换方案(即仅替换 num_cached_tokens 相关的计算)。作者 markmc 接受了此反馈,表示“公平...我可以稍后更进一步重构,如果它有价值的话”,这解释了最终提交相对简洁的变更内容。
  3. 引用历史讨论:markmc 在评论中引用了历史 PR #26813 中的相关讨论,其中提到了关于无效块处理中应包含基于失败块计算出的后续块的问题,这提供了本次变更的额外上下文。

实现拆解

核心变更集中在 vllm/v1/core/sched/scheduler.py 文件的两个函数上:

  1. 参数与签名变更_update_requests_with_invalid_blocks_handle_invalid_blocks 函数新增 num_scheduled_tokens: dict[str, int] 参数,用于接收请求 ID 到其已调度令牌数的映射。
  2. 核心逻辑统一:在 _update_requests_with_invalid_blocks 内部,原先根据请求状态 (WAITING_FOR_REMOTE_KVS) 分别使用 request.num_computed_tokensrequest.num_cached_tokens 计算 req_num_computed_tokens 的分支被移除。取而代之的是统一的计算逻辑:req_num_computed_tokens = request.num_computed_tokens - num_scheduled_tokens.get(req_id, 0)。该逻辑旨在计算“已实际计算且已缓存”的令牌数,即从总计算数中扣除本轮已调度但可能因块加载失败而尚未计算的令牌。
  3. 状态更新同步:在后续需要调整 request.num_computed_tokens 的地方,原先是将其设置为 request.num_cached_tokens,现在则统一设置为新计算出的 req_num_computed_tokens
文件 模块 状态 重要度
vllm/v1/core/sched/scheduler.py scheduler modified 9.0

关键符号

_update_requests_with_invalid_blocks _handle_invalid_blocks

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

无效块驱逐的性能优化 性能

gemini-code-assist[bot] 指出,对于新分配的空无效块,直接 `free()` 可能比加入 `blocks_to_evict` 更高效。markmc 回应,在特定场景下仍需驱逐所有后续块,并最终确认现有逻辑正确。

结论:无需改动,现有逻辑在处理包含新调度令牌的后续块时是正确的。 · 已解决

实现方案的简化 设计

orozery 在 Issue 评论中提出变更可以更简单(仅替换 `num_cached_tokens` 的计算)。markmc 接受了反馈,表示可以稍后再进行更深度的重构。

结论:采纳了更简洁的实现方案,更深度的重构留待未来。 · 已解决

风险与影响

  1. 计算逻辑错误风险:核心风险在于 req_num_computed_tokens = request.num_computed_tokens - num_scheduled_tokens.get(req_id, 0) 这一新计算逻辑的正确性。如果 num_scheduled_tokens 的映射关系不准确(例如,未涵盖所有相关请求或数值错误),可能导致令牌计数截断位置错误,进而引发缓存管理问题(如过早释放仍需要的块)或影响请求的后续调度。
  2. 边界条件处理风险:移除对 request.num_cached_tokens 的直接依赖后,需要确保在同步加载、异步加载以及可能涉及块共享的复杂场景下,新的统一计算逻辑均能正确工作。
  3. 测试覆盖风险:变更涉及核心调度器的错误处理路径,通常此类路径的测试覆盖可能不如主流程完善。尽管 PR 已合并,但需确保相关单元测试和集成测试充分覆盖了 KV 加载失败的各种情况(包括共享块失效)。
  1. 对系统的影响:该重构简化了调度器中处理 KV 缓存加载失败的核心逻辑,使代码更清晰、更统一,减少了因状态差异导致的特殊处理。这有望提高代码的可维护性,并为未来相关的统计和错误处理改进(如 PR body 提及的 #37460)扫清障碍。
  2. 对用户的影响:作为内部重构,除非 num_scheduled_tokens 的传递或新计算逻辑存在缺陷并导致调度或缓存错误,否则最终用户应无感知。主要影响对象是维护和开发 vLLM 调度器与 KV 连接器模块的工程师。
  3. 对团队的影响:变更展示了如何通过引入参数来统一不同场景下的计算,是一个值得学习的代码简化案例。与历史 PR (#26813, #35223, #37460) 的关联表明,团队正在持续演进和完善 KV 缓存失效恢复机制。
核心路径变更 计算逻辑调整

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论