Prhub

#7107 [PD Disaggregation] Write the cache of preempted req to storage and refine PD Disaggregation

PaddlePaddle/FastDeploy · 作者 juncaipeng · 合并时间 2026-04-01 13:15

分析状态 已生成
文件变更 5提交数 3 · 评论 16
代码增减 +35 / -19
Feature KVCache Scheduler Optimization bugfix

执行摘要

优化抢占请求处理,将 KV cache 写入 storage 并调整调度逻辑以避免死锁。

根据PR body,主要动机包括:1) 优化处理抢占请求,如果开了cache池化,将抢占请求的cache写入storage;2) p实例的请求向d申请block时,d实例考虑给running的请求预留block ids;3) 修复写出cache时会修改request中的prompt_token_ids的bug,确保数据一致性。

该PR值得精读,尤其对于从事调度和缓存优化的工程师。重点关注:

  • 调度锁内同步I/O操作的设计权衡,可借鉴以避免类似性能瓶颈。
  • 类型处理的一致性问题,提醒在跨模块开发时需严格遵循类型约定。
  • 环境变量默认值设置对系统行为的影响,建议在实际部署中评估I/O开销。
讨论亮点

Review中核心讨论点:

  • Copilot指出环境变量注释拼写错误('preemted'应改为'preempted')和默认值设置问题,建议将默认值从'1'改为'0'以避免意外I/O开销,但未在PR中修改。
  • Copilot警告在resource_manager_v1.py的_trigger_preempt函数中持有调度锁同步调用write_cache_to_storage,可能阻塞调度线程并增加尾延迟,建议移出锁或异步执行,但作者未回应此风险。
  • Copilot提出类型一致性问题:在prefix_cache_manager.py中,当kvcache_storage_backend非'attention_store'时,token_ids传入None而非空列表,可能违反类型约定,建议统一处理,但未修改。
  • Copilot强调缺少对新逻辑的单元测试覆盖,可能影响后续回归测试,作者未补充测试。
  • 作者juncaipeng解释部分修改原因,如避免死锁卡住和减少跨进程数据传输量。

实现拆解

实现拆解为以下模块:

  1. 缓存管理模块(prefix_cache_manager.py):修改can_allocate_gpu_blocks函数,新增try_free_gpu_blocks参数以控制是否尝试释放GPU blocks,避免潜在死锁;修复write_cache_to_storage和write_cache_to_storage_decode函数中token_ids的构造逻辑,防止修改原始请求数据。
  2. 调度模块(resource_manager_v1.py):在_trigger_preempt函数中新增逻辑,当环境变量FD_SAVE_OUTPUT_CACHE_FOR_PREEMPTED_REQUEST开启时,调用cache_manager.write_cache_to_storage或write_cache_to_storage_decode将抢占请求的cache写入storage;调整preallocate_resource_in_d函数,使用_get_can_schedule_prefill_threshold_block计算总需block数,为运行请求预留资源。
  3. 环境配置模块(envs.py):新增环境变量FD_SAVE_OUTPUT_CACHE_FOR_PREEMPTED_REQUEST,默认值为1(开启),控制是否在抢占时保存cache到storage。
  4. 缓存传输模块(cache_transfer_manager.py):修改read_storage_task函数,在token_ids为空时传入None,减少数据传输量。
  5. 引擎模块(common_engine.py):将日志级别从error调整为warning,降低错误处理的噪音。
文件 模块 状态 重要度
fastdeploy/engine/sched/resource_manager_v1.py Scheduler modified 8.0
fastdeploy/cache_manager/prefix_cache_manager.py KVCache modified 7.0
fastdeploy/envs.py Configuration modified 5.0
fastdeploy/cache_manager/cache_transfer_manager.py Cache Transfer modified 4.0
fastdeploy/engine/common_engine.py Engine modified 3.0

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

关键符号

can_allocate_gpu_blocks write_cache_to_storage write_cache_to_storage_decode _trigger_preempt preallocate_resource_in_d request_match_blocks

评论区精华

环境变量拼写和默认值问题 style

Copilot 指出注释中 'preemted' 拼写错误应改为 'preempted',并建议默认值从 '1' 改为 '0' 以避免默认开启 I/O 行为。

结论:建议未在 PR 中采纳,状态保持开放。 · 待处理

调度锁内同步调用风险 设计

Copilot 警告在 _trigger_preempt 中持有锁同步写 cache 可能阻塞调度线程,建议异步化或移出锁。

结论:作者未回应,风险未解决,可能影响性能。 · unresolved

类型不一致性风险 正确性

Copilot 指出在非 attention_store 后端时,token_ids 传入 None 可能违反类型标注 List[int],建议使用空列表。

结论:未修改,可能引入运行时错误。 · unresolved

缺少单元测试覆盖 测试

Copilot 强调新增的写 cache 逻辑缺少单元测试,Codecov 报告显示覆盖率不足。

结论:未在 PR 中补充测试,回归风险较高。 · unresolved

风险与影响

技术风险具体如下:

  1. 性能风险:在fastdeploy/engine/sched/resource_manager_v1.py的_trigger_preempt函数中,持有锁同步执行write_cache_to_storage,可能因I/O或等待操作阻塞调度线程,影响系统响应时间和并发性。
  2. 正确性风险:fastdeploy/cache_manager/prefix_cache_manager.py中,token_ids在非attention_store后端传入None,而相关任务类型标注为List[int],可能导致后续代码假设非空而引发运行时错误。
  3. 兼容性风险:环境变量FD_SAVE_OUTPUT_CACHE_FOR_PREEMPTED_REQUEST默认开启(值为1),改变历史默认行为,可能引入额外I/O开销,影响现有部署性能。
  4. 测试覆盖风险:新增的写cache逻辑缺少单元测试,Codecov报告显示patch覆盖率仅57.14286%,增加回归风险。

影响评估:

  • 用户影响:启用该功能后,抢占请求的KV cache可持久化到storage,提高缓存复用率,减少重新计算开销,潜在提升系统吞吐和响应时间;但默认开启可能增加I/O延迟,需用户根据场景权衡。
  • 系统影响:优化调度逻辑减少死锁风险,增强PD Disaggregation的稳定性和资源利用率;日志级别调整降低错误日志噪音。
  • 团队影响:新增环境变量需团队在部署时配置,类型不一致问题可能增加维护复杂度;review中未解决的讨论点提示设计权衡需后续关注。影响程度中等,涉及核心调度和缓存管理路径。
调度锁内 I/O 操作 类型不一致 缺少测试覆盖 默认行为变更

关联 Issue

未识别关联 Issue

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

完整报告

执行摘要

本PR优化了FastDeploy中PD Disaggregation场景下的抢占请求处理,通过将抢占请求的KV cache写入storage后端以提升缓存复用率,并调整调度逻辑避免死锁。关键变更包括新增环境变量控制、调度器写cache逻辑和缓存管理函数参数调整,影响系统性能和稳定性,但review中未解决锁内调用和类型一致性等风险,需后续关注。

功能与动机

根据PR作者juncaipeng的描述,此变更旨在解决三个核心问题:

  • 优化抢占请求处理:当启用缓存池化时,抢占请求的KV cache应写入storage,以便后续请求复用,减少重复计算开销。
  • 资源预留调整:p实例向d实例申请block时,d实例需为运行中的请求预留block ids,避免资源竞争导致的调度失败。
  • 修复数据修改bug:原write_cache_to_storage函数在构造token_ids时会意外修改request中的prompt_token_ids,本PR通过引入中间变量input_token_ids修复此问题。

实现拆解

实现方案按模块拆解如下:
| 模块 | 关键文件 | 主要变更 |
|------|----------|----------|
| 调度器 | fastdeploy/engine/sched/resource_manager_v1.py | 在_trigger_preempt函数中添加条件检查,当环境变量FD_SAVE_OUTPUT_CACHE_FOR_PREEMPTED_REQUEST开启且storage backend启用时,调用write_cache_to_storagewrite_cache_to_storage_decode;调整preallocate_resource_in_d函数使用_get_can_schedule_prefill_threshold_block计算总需blocks。 |
| 缓存管理器 | fastdeploy/cache_manager/prefix_cache_manager.py | 修改can_allocate_gpu_blocks函数,新增try_free_gpu_blocks参数(默认True),在request_match_blocks中设为False以避免死锁;修复write_cache_to_storagewrite_cache_to_storage_decode函数,防止修改原始token_ids。 |
| 环境配置 | fastdeploy/envs.py | 新增环境变量FD_SAVE_OUTPUT_CACHE_FOR_PREEMPTED_REQUEST,默认值1,控制是否在抢占时保存cache到storage。 |
| 缓存传输 | fastdeploy/cache_manager/cache_transfer_manager.py | 调整read_storage_task函数,在token_ids为空时传入None,减少跨进程数据量。 |
| 引擎 | fastdeploy/engine/common_engine.py | 将日志级别从error改为warning,降低错误处理噪音。 |

评论区精华

Review讨论中,Copilot作为主要评论者,提出了多项关键洞察:

  • 环境变量细节

    "这里的注释里 preemted 拼写错误,建议更正为 preempted,避免后续搜索/文档引用时产生歧义。"
    "这个环境变量是新引入的'是否开启'开关,但默认值设为 '1' 会导致默认启用写入 storage 的行为,可能带来额外 I/O 与延迟,并改变历史默认行为。"

  • 设计风险

    "在 schedule() 持有 self.lock 的情况下,这里同步调用 write_cache_to_storage*() 可能会把潜在的 I/O/等待放到调度锁里,导致调度线程长时间阻塞甚至影响并发。"

  • 类型一致性

    "ReadStorageTask/CacheTask 的 token_ids 在类型标注里是 List[int] 且为必填字段,但这里在非 attention_store 后端时传入 None。建议统一传入空列表([])或把 CacheTask.token_ids 改为 Optional[List[int]]。"

  • 测试覆盖

    "新增的'preempt 时写 cache 到 storage'逻辑目前在单测中没有覆盖...建议补充对应的单元测试,避免该关键路径在后续重构中回归。"
    作者juncaipeng在部分评论中简要解释修改原因,如"避免可能的死锁卡住"和"减少跨进程传输的数据量",但未直接回应风险建议。

风险与影响

技术风险

  1. 性能瓶颈:调度锁内同步I/O操作可能阻塞线程,放大抢占路径的尾延迟,影响系统响应时间。
  2. 运行时错误:token_ids传入None违反类型约定,若后续代码无条件操作可能引发异常。
  3. 行为变更:环境变量默认开启改变历史行为,未评估场景下可能引入不必要I/O开销。
  4. 回归风险:缺少单元测试,Codecov报告显示patch覆盖率仅57.14286%,新增逻辑易在重构中失效。

影响评估

  • 正面影响:提升缓存复用率,减少抢占请求的重新计算,优化PD Disaggregation资源利用率。
  • 负面影响:默认开启写cache可能增加存储I/O和延迟;未解决的设计风险可能降低系统并发性。
  • 团队影响:需关注环境变量配置和类型约定,review中未决问题提示后续开发需加强设计评审。

关联脉络

从同仓库近期历史PR分析,本PR与多个KVCache和Scheduler相关变更形成关联脉络:

  • PR #6929:修复KVCache中hash边界比较bug,共享缓存管理逻辑,显示前缀缓存计算的持续优化。
  • PR #6992:新增中断请求端点,涉及Scheduler和KVCache资源管理,与本PR的抢占处理互补。
  • PR #7046 和 #7075:关于KVCache storage cache的锁添加与回滚,突显缓存并发控制的复杂性,与本PR中锁内调用风险相呼应,提示团队在类似场景需谨慎权衡同步与异步设计。
    整体上,这些PR共同推动FastDeploy在缓存持久化和调度优化方向的演进,本PR作为其中一环,强化了抢占场景下的缓存复用能力,但遗留的设计争议需在后续迭代中解决。

参与讨论