执行摘要
本次PR修复了PD分离(disaggregation)场景下prefill节点未及时更新prefix cache命中信息导致的低命中率问题,通过在调度器的preallocate_resource_in_p方法中主动调用update_cache_blocks并调整角色排除逻辑,确保cache状态正确同步。变更直接影响PD分离模式的推理性能,但参数选择争议未解决可能遗留cache状态不一致风险。
功能与动机
在PD分离场景中,prefill节点负责处理prompt的预填充,但成功分配GPU block后未更新prefix cache的命中信息,导致已命中的cache无法被正确记录,命中率异常偏低,影响推理性能。PR body明确指出:“prefill 节点在通过 _allocate_gpu_blocks 成功分配block后,没有调用 update_cache_blocks 更新 cache block 状态,导致已命中的 prefix cache 无法被正确记录”。
实现拆解
仅修改fastdeploy/engine/sched/resource_manager_v1.py文件,包含两处关键改动:
-
调整_allocate_decode_and_extend中的角色排除逻辑:
python
if (
self.config.cache_config.enable_prefix_caching
and self.config.scheduler_config.splitwise_role != "decode"
and self.config.scheduler_config.splitwise_role != "prefill" # 新增排除prefill
):
避免prefill节点在_free_blocks_when_stop中重复更新cache block状态。
-
在preallocate_resource_in_p中主动更新cache block:
python
self.cache_manager.update_cache_blocks(
request, self.config.cache_config.block_size, request.need_prefill_tokens
)
prefill节点分配block后立即调用,使用need_prefill_tokens作为已计算token数量。
评论区精华
review中聚焦于update_cache_blocks参数选择的正确性:
- fastdeploy-bot指出:“使用
request.need_prefill_tokens 作为 update_cache_blocks 的第三个参数需要进一步说明...当只有部分 prompt tokens 命中 cache 时,使用 need_prefill_tokens 可能导致 cache tree 中记录的 cached blocks 数量与实际不一致。”
- Copilot进一步解释:“传入
request.need_prefill_tokens 会让 PrefixCacheManager 认为整段 prompt 都已‘计算完成’,从而为 cache miss 部分也提前创建 radix tree 节点并绑定新分配的 GPU block...可能造成错误复用或状态污染。”
但作者未回应这些建议,最终代码仍使用need_prefill_tokens。
风险与影响
风险:
- cache状态不一致:当部分prompt命中cache时,使用
need_prefill_tokens(所有prompt tokens)而非num_computed_tokens(已命中tokens)可能导致cache tree记录不准确。
- 错误复用风险:可能为未填充的GPU block创建radix tree节点,后续请求匹配到未完成的cache。
- 回归风险:变更涉及调度器核心路径,但缺少单元测试(PR body说明需端到端PD分离环境验证)。
影响:
- 正面:修复后应显著提升PD分离场景的prefix cache命中率,改善推理性能。
- 范围:仅影响PD分离模式,对非分离模式无影响。
- 用户:透明修复,无需配置变更。
关联脉络
本次修复是FastDeploy在PD分离架构优化中的一环:
- PR #7241(移除KV Cache块数上限)同样关注cache利用率提升。
- PR #7299(移除CacheManager与WorkerProcess间IPCLock)优化了cache相关组件交互。
- PR #7323(支持PD分离模式下MTP超重叠)同样针对PD分离模式进行调度优化。
这些PR共同反映了团队对PD分离场景性能的持续打磨,特别是调度器与cache管理器的协同优化。
参与讨论