[BugFix][PD Disaggregation][KVCache] Fix low cache hit rate in PD split (disaggregation) scenario#7364
Conversation
…it scenario ## Motivation 在 PD 分离场景下,decode 节点在接收 prefill 节点转发的请求后,没有及时更新 cache block 的命中信息, 导致 prefix cache 命中率低,影响推理性能。 ## Modifications 1. 在 `_free_blocks_when_stop` 方法中,额外排除 prefill 节点(`splitwise_role == "prefill"`) 的 cache block 更新,避免 prefill 节点重复更新 cache 导致状态混乱。 2. 在 decode 节点分配请求(`_alloc_requests_with_cache`)成功后,主动调用 `update_cache_blocks` 使用 `need_prefill_tokens` 更新 cache block 信息, 确保 decode 节点能正确感知已命中的 prefix cache。
|
Thanks for your contribution! |
PaddlePaddle-bot
left a comment
There was a problem hiding this comment.
🤖 AI Code Review |
2026-04-13
📋 Review 摘要
PR 概述:修复 PD 分离场景下 D 节点 prefix cache 命中率偏低的问题,通过调整 P 节点的 cache block 更新时机
变更范围:fastdeploy/engine/sched/resource_manager_v1.py
影响面 Tag:[PD Disaggregation] [KVCache]
📝 PR 规范检查
- ✅ 标题包含有效的
[BugFix]、[PD Disaggregation]、[KVCache]Tag - ✅ PR 描述包含 Motivation 和 Modifications 章节
- ✅ 包含 Usage 或 Command 验证步骤
- ✅ Checklist 标注无单元测试原因
说明:PR 描述中的方法名与实际修改不符(描述中提到 _free_blocks_when_stop 和 _alloc_requests_with_cache,实际修改的是 _allocate_decode_and_extend() 和 preallocate_resource_in_p()),建议下次检查确保描述与实际代码一致。
问题
| 级别 | 文件 | 概述 |
|---|---|---|
| 🟡 建议 | resource_manager_v1.py:1380 |
update_cache_blocks 参数选择可能导致 cache state 不一致 |
总体评价
修复思路合理,通过在 preallocate_resource_in_p() 中新增 update_cache_blocks 调用,确保 P 节点正确更新 cache tree,同时避免 prefill 循环中的重复更新。但修改 2 中使用 request.need_prefill_tokens 作为参数的合理性需要进一步说明。
| self.req_dict[request.request_id] = allocated_position | ||
|
|
||
| self.cache_manager.update_cache_blocks( | ||
| request, self.config.cache_config.block_size, request.need_prefill_tokens |
There was a problem hiding this comment.
🟡 建议 在 preallocate_resource_in_p() 中,使用 request.need_prefill_tokens 作为 update_cache_blocks 的第三个参数需要进一步说明。
update_cache_blocks 的第三个参数语义是 num_computed_tokens(已计算的 tokens 数量),而 get_prefix_cached_blocks() 已经设置了 request.num_computed_tokens 为命中的 token 数量(见第 1278 行)。
当只有部分 prompt tokens 命中 cache 时(matched_token_num < need_prefill_tokens):
request.need_prefill_tokens= 所有 prompt tokensrequest.num_computed_tokens= 命中的 tokens
使用 need_prefill_tokens 可能导致 cache tree 中记录的 cached blocks 数量与实际不一致。建议验证在部分 cache 命中场景下,使用 request.num_computed_tokens 是否更合适:
self.cache_manager.update_cache_blocks(
request, self.config.cache_config.block_size, request.num_computed_tokens
)如果使用 need_prefill_tokens 是有意为之(例如让 P 节点统一记录完整 prompt),建议在 PR 描述中补充说明。
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #7364 +/- ##
==========================================
Coverage ? 73.05%
==========================================
Files ? 383
Lines ? 53613
Branches ? 8411
==========================================
Hits ? 39167
Misses ? 11782
Partials ? 2664
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
该 PR 旨在修复 PD 分离(disaggregation)场景下 prefix cache 命中率偏低的问题,通过调整 prefix cache block 状态更新时机/角色来提升推理性能。
Changes:
- 在调度 prefill 逻辑中,进一步限制
update_cache_blocks的触发角色(排除prefill)。 - 在
preallocate_resource_in_p中新增一次update_cache_blocks调用,以期在资源预分配阶段更新 cache block 状态。
Comments suppressed due to low confidence (1)
fastdeploy/engine/sched/resource_manager_v1.py:934
- 这里把 update_cache_blocks 的触发条件改成仅在 splitwise_role 既不是 "decode" 也不是 "prefill" 时才执行(实际只剩 mixed)。但在 v1 splitwise 流程里,P 节点会通过 add_request_in_p 直接把请求放进 running 队列(不会走 waiting->running 那段 update_cache_blocks 逻辑);因此该改动会导致 P 节点在 prefill 过程中 num_computed_tokens 增长时不再更新 radix tree/leaf 记录,新计算出来的 prefix blocks 可能永远不会被纳入 prefix cache,命中率/复用反而会继续偏低。建议明确 splitwise 场景下由哪个角色负责在“prefill 真正完成计算后”调用 update_cache_blocks:要么恢复 P 节点在此处更新(并在其它位置避免重复/冲突),要么把更新迁移到 decode 或 cache_messager 的确定时机,并确保不会在计算完成前把未填充 block 写入树。
if (
self.config.cache_config.enable_prefix_caching
and self.config.scheduler_config.splitwise_role != "decode"
and self.config.scheduler_config.splitwise_role != "prefill"
):
self.cache_manager.update_cache_blocks(
request, self.config.cache_config.block_size, request.num_computed_tokens
)
| self.cache_manager.update_cache_blocks( | ||
| request, self.config.cache_config.block_size, request.need_prefill_tokens |
There was a problem hiding this comment.
preallocate_resource_in_p 里调用 update_cache_blocks 时传入 request.need_prefill_tokens 会让 PrefixCacheManager 认为整段 prompt 都已“计算完成”,从而在 mm_build_path 中为 cache miss 部分也提前创建 radix tree 节点并绑定新分配的 GPU block。由于这些 block 在真正的 prefill forward 前还没有写入有效 KV,这会让后续请求有机会匹配到未填充/未完成的 cache,造成错误复用或状态污染。建议这里改为使用 request.num_computed_tokens(即命中后可直接复用的已计算 token 数)来做 hit 记录,或者把 update_cache_blocks 延后到 prefill 计算完成并确认对应 block 已填充之后再调用。
| self.cache_manager.update_cache_blocks( | |
| request, self.config.cache_config.block_size, request.need_prefill_tokens | |
| # Only record the prefix tokens that are already computed and safe to reuse. | |
| computed_prefix_tokens = max( | |
| 0, min(request.num_computed_tokens, request.need_prefill_tokens) | |
| ) | |
| self.cache_manager.update_cache_blocks( | |
| request, self.config.cache_config.block_size, computed_prefix_tokens |
…it scenario (PaddlePaddle#7364) ## Motivation 在 PD 分离场景下,decode 节点在接收 prefill 节点转发的请求后,没有及时更新 cache block 的命中信息, 导致 prefix cache 命中率低,影响推理性能。 ## Modifications 1. 在 `_free_blocks_when_stop` 方法中,额外排除 prefill 节点(`splitwise_role == "prefill"`) 的 cache block 更新,避免 prefill 节点重复更新 cache 导致状态混乱。 2. 在 decode 节点分配请求(`_alloc_requests_with_cache`)成功后,主动调用 `update_cache_blocks` 使用 `need_prefill_tokens` 更新 cache block 信息, 确保 decode 节点能正确感知已命中的 prefix cache。
|
✅ Cherry-pick successful! Created PR: #7387 |
…it scenario (#7364) (#7387) ## Motivation 在 PD 分离场景下,decode 节点在接收 prefill 节点转发的请求后,没有及时更新 cache block 的命中信息, 导致 prefix cache 命中率低,影响推理性能。 ## Modifications 1. 在 `_free_blocks_when_stop` 方法中,额外排除 prefill 节点(`splitwise_role == "prefill"`) 的 cache block 更新,避免 prefill 节点重复更新 cache 导致状态混乱。 2. 在 decode 节点分配请求(`_alloc_requests_with_cache`)成功后,主动调用 `update_cache_blocks` 使用 `need_prefill_tokens` 更新 cache block 信息, 确保 decode 节点能正确感知已命中的 prefix cache。 Co-authored-by: kevin <chengyf112@gmail.com>
Motivation
在 PD 分离(disaggregation)场景下,prefill 节点收到请求后,未能及时更新 prefix cache block 的命中信息,导致 prefix cache 命中率异常偏低,影响推理性能。
具体问题:
_allocate_gpu_blocks成功分配block后,没有调用update_cache_blocks更新 cache block 状态,导致已命中的 prefix cache 无法被正确记录Modifications
统一 prefill 节点的 cache block 更新:在
_free_blocks_when_stop方法中,新增对splitwise_role != "prefill"的排除判断,避免 prefill 节点重复更新 cache block 状态。prefill 节点主动更新 cache block:在
preallocate_resource_in_p方法中,prefill 节点成功分配block后,主动调用update_cache_blocks(使用need_prefill_tokens)。Usage or Command
启动 PD 分离服务进行验证:
修复后,prefill 节点日志中 prefix cache 命中率应显著提升。
Checklist
pre-commitbefore commit.releasebranch, make sure the PR has been submitted to thedevelopbranch, then cherry-pick it to thereleasebranch with the[Cherry-Pick]PR tag.