前缀复用、回收与退化路径#
这章解决什么问题#
上一章已经解释了 scheduler、batch 和 KV cache 怎样一起工作,但还有一个更接近真实性能与资源行为的问题:为什么有时 prefix reuse 很有效,有时又会明显退化?为什么有时缓存看起来还在,却仍然要重新做大量计算?这些问题决定了调度与内存章节能不能真正落到运行时行为上。
这一章要补的,正是“缓存不是只会存在,还会失效、退化、被回收”这一层。没有这一层,读者很容易把 cache 理解成一个总是带来收益的静态结构,而不是一个持续参与权衡的动态机制。
为什么前缀复用不是“命中就结束”#
从 RadixCache、ChunkCache 以及相关 tree_cache 路径看,prefix reuse 本质上依赖的是“请求前缀与已有状态能否以当前策略被匹配并继续复用”。这意味着缓存收益不仅取决于是否有相同前缀,还取决于当前缓存策略、page 对齐、allocator 状态以及 batch 形成方式。
换句话说,“前缀相同”并不自动等于“运行时表现就好”。对读者来说,这一层很重要,因为它把“缓存命中”从一个二元判断变成了一个运行时条件组合问题。
RadixCache、ChunkCache 与策略切换#
前一章已经提到 scheduler.py 会根据配置在 ChunkCache、RadixCache、SWARadixCache、MambaRadixCache 以及其他变体之间做选择。这里再往前走一步,需要解释为什么这件事本身就意味着“缓存策略”不是固定的。
chunk_cache.py 的注释强调它用于 chunked prefill 且在 RadixCache 关闭时使用;radix_cache.py 的注释则明确它是管理 KV cache 的 radix tree 数据结构。两者共同说明:不同缓存实现不是“同一层的不同名字”,而是对复用方式、匹配粒度和状态维护方式做出的不同选择。
回收为什么会成为第一层问题#
一旦 cache 被真正用于运行中的请求,系统迟早要面对回收问题。回收之所以重要,不只是为了节省内存,还因为它直接决定“下一批请求还能不能继续享受既有状态”。也就是说,回收并不是 cache 章节末尾的 housekeeping,而是 runtime 收益能否持续的核心组成部分。
这也是为什么这一章要和前一章连着看。前一章讲的是“状态怎样被放进去”,这一章讲的是“状态怎样被保住、怎样被丢掉、丢掉之后会表现成什么”。把两者合起来,调度与内存这一节才真正完整。
一个更贴近运行时表现的图#
下面这张图专门解释“缓存收益如何形成,又怎样退化”。它不是另一张结构图,而是把复用、回收和退化放在同一条状态线上。
flowchart TD
A["新请求到达"] --> B["前缀匹配"]
B -->|命中| C["复用已有 cache state"]
B -->|未命中| D["重新 prefill / 追加计算"]
C --> E["进入 batch 继续 decode"]
D --> E
E --> F["状态继续驻留"]
F --> G{"是否需要回收 / 退化"}
G -->|否| H["后续请求继续受益"]
G -->|是| I["eviction / fallback / reuse 下降"]
I --> J["后续请求重新承担更多计算"]这张图比前一章的调度/KV 流图多解释了“收益并不是静态的”。只要缓存进入回收和退化区间,后续请求就会重新承担更多 prefill 或状态构建成本。
典型退化现象与阅读入口#
如果你观察到的是“明明有相似请求,但收益不像预期那么明显”,优先看 tree_cache 的匹配和 reuse 逻辑。
如果你观察到的是“内存一直在涨,回收看起来不及时”,优先看 allocator、memory pool 和 cache 回收路径。
如果你观察到的是“策略切换后行为完全不同”,就要回头确认当前到底是 RadixCache 语义,还是 ChunkCache 语义。
这些现象之所以值得单独列出来,是因为它们比纯术语更接近维护者视角。读者离开这一章之后,不应该只是记住几种 cache 名称,而应该知道“当 cache 表现不如预期时,先从哪条线追”。
本章对应哪些代码路径#
这一章最重要的锚点包括 python/sglang/srt/mem_cache/radix_cache.py、python/sglang/srt/mem_cache/chunk_cache.py、python/sglang/srt/mem_cache/memory_pool.py、python/sglang/srt/managers/scheduler.py 与 test/registered/unit/mem_cache/test_radix_cache_unit.py 一类验证路径。
如果要继续下钻,比较稳的顺序是:先看 cache 实现与注释,再看 scheduler 如何持有 tree_cache,最后回到 mem_cache 相关测试看这些路径被怎样验证。这样读,能把“结构、行为、验证”三层连起来。
小结#
缓存这一层的价值,不只是节省算力,更在于它怎样持续影响后续请求的 runtime 轨迹。理解前缀复用、回收和退化路径之后,调度与内存这一节才真正从“机制介绍”升级成“运行时判断框架”。
叶王 © 2013-2026 版权所有。如果本文档对你有所帮助,可以请作者喝饮料。