Prhub

#29428 Let cache backend do not couple with owned committed kv details and avoid kv_committed_freed/kv_overallocated_freed fields

原始 PR 作者 fzyzcjy 合并时间 2026-07-15 14:43 文件变更 24 提交数 9 评论 1 代码增减 +121 / -154

执行摘要

解耦缓存后端与 KV committed 细节,移除记账标志

在 stacked refactor chain 中,需要解耦缓存后端与请求的 owned committed KV 细节。之前缓存后端主动调用 pop_committed_kv_cache 来获取长度并标记已释放,这要求缓存内部了解请求层的状态标志。通过将长度作为参数传入,并且依赖于先前的证明(pop_committed_kv_cache / pop_overallocated_kv_cache 总是成对调用),可以安全地移除这些标志和方法,降低维护复杂度。

此 PR 是系列重构中的一环,展示了如何通过接口解耦来简化状态管理。推荐希望理解 SGLang KV 缓存架构的工程师精读,特别是 cache_finished_req 签名变化和 effective_kv_committed_len 的引入。

讨论亮点

仅 Gemini Code Assist 机器人发表自动评论,总结变更并指出无其他审查评论。无实质性的设计讨论或争议。

实现拆解

  1. 移除状态标志与弹出方法:在 python/sglang/srt/managers/schedule_batch.pyReq.__init__ 中删除 self.kv_committed_freedself.kv_overallocated_freed 字段;删除 pop_committed_kv_cachepop_overallocated_kv_cache 方法;将 _cache_commit_len 重命名为 effective_kv_committed_len(功能不变)。

  2. 统一缓存后端接口:在所有缓存实现的 cache_finished_req 方法签名中增加关键字参数 kv_len_to_handle: int,要求调用者显式传入要处理的 KV 长度。受影响文件包括:mamba_radix_cache.pyradix_cache_cpp.pychunk_cache.pyunified_radix_cache.pyswa_radix_cache.pyradix_cache.pypure_swa_radix_cache.pylmc_radix_cache.py 等。

  3. 更新调用点:所有原先调用 pop_committed_kv_cache() 的地方改为调用 req.effective_kv_committed_len() 并将结果传递给 cache_finished_req。这确保了行为一致。

  4. 清理测试与无关代码:在 schedule_batch.pyreset_for_retract 中删除对 kv_committed_freedkv_overallocated_freed 的复位;在 streaming_session.py 中删除不再需要的 _mark_kv_freed 方法(因为不再需要标记已释放)。相应更新测试文件。

文件 模块 状态 重要度
python/sglang/srt/managers/schedule_batch.py 调度器 modified 7.68
python/sglang/srt/mem_cache/mamba_radix_cache.py 缓存层 modified 6.58
python/sglang/srt/mem_cache/chunk_cache.py 缓存层 modified 6.33

关键符号

effective_kv_committed_len cache_finished_req

关键源码片段

python/sglang/srt/managers/schedule_batch.py core-logic

核心变更文件:移除了 kv_committed_freed / kv_overallocated_freed 字段和 pop 方法,重命名方法为 effective_kv_committed_len,影响所有使用这些符号的代码。

# python/sglang/srt/managers/schedule_batch.pyclass Req:
    def __init__(self, ...):
        # For req-level memory management
        self.kv_committed_len = 0
        self.kv: ReqKvInfo = ReqKvInfo(kv_allocated_len=0, swa_evicted_seqlen=0)
        # kv_committed_freed 和 kv_overallocated_freed 已被移除,不再需要
        ...
​
    def effective_kv_committed_len(self) -> int:
        # 原 _cache_commit_len,功能不变
        # 仅在 strip_thinking_cache 时可能返回 min(kv_committed_len, len(origin_input_ids))
        if get_server_args().strip_thinking_cache and self.reasoning_tokens > 0:
            return min(self.kv_committed_len, len(self.origin_input_ids))
        return self.kv_committed_len
​
    # pop_committed_kv_cache 和 pop_overallocated_kv_cache 已被删除
    # 外部代码不再通过 pop 获得长度并修改状态,而是直接调用 effective_kv_committed_len
python/sglang/srt/mem_cache/mamba_radix_cache.py core-logic

缓存后端之一,cache_finished_req 签名改动:不再调用 req.pop_committed_kv_cache,而是通过 kv_len_to_handle 参数传入长度。

# python/sglang/srt/mem_cache/mamba_radix_cache.pyclass MambaRadixCache:
    def cache_finished_req(
        self, req: Req, is_insert: bool = True, *, kv_len_to_handle: int
    ) -> None:
        """Cache request when it finishes."""
        # 不再调用 req.pop_committed_kv_cache(),长度由调用者传入
        if self.disable:
            kv_indices = self.req_to_token_pool.req_to_token[
                req.req_pool_idx, :kv_len_to_handle
            ]
            self.token_to_kv_pool_allocator.free(kv_indices)
            self.req_to_token_pool.free_mamba_cache(req)
            return
​
        token_ids = (req.origin_input_ids + req.output_ids)[:kv_len_to_handle]
        kv_indices = self.req_to_token_pool.req_to_token[
            req.req_pool_idx, :kv_len_to_handle
        ]
        # ... 后续逻辑保持不变

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

主要风险在于调用方必须确保传入正确的 kv_len_to_handle,否则可能导致 KV 缓存泄漏(传少了)或释放正在使用的内存(传多了)。由于该值基于 effective_kv_committed_len(),而此方法逻辑与原 _cache_commit_len 相同,且 pop 方法原本就是返回该值,因此风险较低。另外,移除了 kv_committed_freed 断言,可能隐藏重复释放的问题,但根据作者说明,先前的证明表明这些标记在实际中是冗余的。

对用户透明:功能无变化,性能无影响。对系统:代码结构更清晰,缓存后端不再依赖请求层的实现细节,降低了耦合。对团队:后续维护更容易,新增缓存实现时无需处理释放标志。

需确保调用者传递正确长度 移除断言可能隐藏重复释放

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论