DeepSeekV4分层缓存架构:Tair联手SGLang
摘要
先说几个核心判断。 DeepSeek V4 在注意力机制上走了一条混合路线——CSA(压缩稀疏注意力
先说几个核心判断。
DeepSeek V4 在注意力机制上走了一条混合路线——CSA(压缩稀疏注意力)和 HCA(混合上下文注意力)的组合。直观理解就是:CSA 用低倍率压缩配合 sparse top-k 检索来保留长程信息,HCA 用高倍率压缩提供全局上下文补充,最后 SWA(滑动窗口注意力)负责最近窗口内的精细建模。
这个设计确实聪明,但也给推理系统出了个难题:同一个 token,在不同的注意力路径里对应着完全不同的物理形态。最近窗口需要的是原始 KV,长历史被压缩成 C4 或 C128,C4 还得配一个 indexer 做稀疏检索。如果系统还是把 KV Cache 当作一块连续 buffer 来管,显然是接不住这样的复杂度。
阿里云 Tair KVCache 团队和 SGLang 社区为此做了一套面向 Prefill 和 Decode 两个阶段的分层缓存架构。实测结果挺有意思:在多轮对话场景下,Prefill 配合 HiCache 吞吐提升了接近 3 倍;Decode 侧通过 HiSparse 的分层 SparseAttention 机制,释放出来的显存让 BatchSize 直接翻了 5 到 10 倍。
下面我们就顺着这套架构的脉络往下走,重点看看 Shadow Radix、UnifiedRadixTree、HiCache 和 HiSparse 各自的职责和协作边界。整个链路可以概括为:
- SGLang 提出了 Shadow Radix,提供了一层统一的逻辑地址,让 prefix cache 和 scheduler 不用直接面对 SWA、C4、C128 这些物理细节。
- HiCache 和 HiSparse 分别服务于 prefill 与 decode:前者在存储层通过 GPU → Host → Storage 的三级架构来扩展前缀复用能力;后者在计算层通过降低 C4 sparse attention 在 decode 阶段的 GPU 常驻 KV 来释放显存。
1. Shadow Radix:一棵逻辑树对应五种物理形态
DeepSeek V4 的 attention kvcache 由几条不同的数据路径组成。距离当前位置最近的 128 个 token 走 sliding window attention,远距离的历史以 C4 或 C128 的压缩 KV 形式参与计算;C4 layer 还需要通过 indexer 选出当前步要访问的 sparse kvcache。

图 1:DeepSeek V4 的每层 attention 同时面对最近窗口和压缩历史。图来自SGLang DeepSeek-V4 Day-0 blog。
Shadow Radix 的目标很清晰——让不同物理 pool 共用一套逻辑坐标。在 SGLang 里,radix tree 保存的是 full logical index,这个 index 会出现在 req.prefix_indices、req_to_token_pool.req_to_token、ForwardBatch.out_cache_loc 等位置。
需要理解的是,full logical index 并不等于某个具体的物理 KV 地址。它更像是一条稳定的 token 地址线:scheduler 用它描述 prefix 命中,request table 用它描述请求上下文,backend 再根据 layer 类型把它翻译到具体的 pool。
full logical index
-> SWA index: 最近窗口里的 raw KV
-> C4 compressed index: 4:1 压缩后的历史 KV
-> C128 compressed index: 128:1 压缩后的历史 KV
-> C4 indexer index: 稀疏检索用的量化 key
-> compress state ring: 继续压缩所需的 rolling state

图 2:Shadow Radix 使用一棵逻辑前缀树维护 full logical index,再由 backend 把同一段逻辑前缀投影到 SWA、C4、C128、indexer 和 state pools。
具体的投影规则也不复杂。SWA 依赖 full_to_swa_index_mapping 完成映射;C4 和 C128 的压缩位置可以直接通过除法推算,比如 raw_out_loc // 4 或 raw_out_loc // 128。compress state 则是先从 full index 翻译到 SWA index,再进入每个 SWA page 所属的 ring index:
swa_page = swa_loc // swa_page_size
state_loc = swa_page * ring_size + (swa_loc % ring_size)

图 3:官方 Shadow Radix storage layout。重点在于同一份 logical slot 在多个物理 pool 中有不同投影,而不是让 radix tree 直接管理每个物理页。
2. 分层缓存架构应对 P/D 不同的显存压力
在 SGLang 的 P/D 分离部署中,Prefill Worker 和 Decode Worker 面对的压力完全不同。Prefill 侧的成本集中在长前缀计算上;Decode 侧的问题更多来自长期 KV 常驻显存——冷 KV 占住显存后,decode batch size 就很难再拉上去。HiCache 和 HiSparse 都引入了 Host 分层,但分别对应着这两个阶段的瓶颈。

图 4:SGLang P/D 分离下的缓存边界。
Prefill Worker 开启 HiCache,用 L2 Host 和 L3 Storage 扩展 prefix KV cache;Decode Worker 开启 HiSparse,只在 C4 sparse attention 的 miss token 上做增量 Host→GPU 加载。
把两者的差异放在一张表里,看得更清楚:
| 机制 | 所在阶段 | 管理对象 | 主要数据路径 | 目标 |
| V4 HiCache | Prefill | prefix KV cache | GPU L1 ↔ Host L2 ↔ Storage L3 | 扩大前缀 KV 的可复用空间,提高长前缀命中率 |
| V4 HiSparse | Decode | C4 sparse attention KV | CPU C4 mirror ↔ GPU hot buffer | 减少 C4 compressed KV 在 GPU 上的常驻占用 |
HiCache 依赖 UnifiedRadixTree 的 prefix match 语义。请求进入 prefill 时,scheduler 先匹配 full logical prefix;如果命中已经 offload 到 Host 或 Storage 的前缀,HiCache 会在 prefill 计算前把必要的 KV load back 到 GPU。
HiSparse 不走这条 prefix match 路径。Decode 每一步,C4 indexer 会选出当前需要访问的 top-k compressed tokens,HiSparse 检查这些 token 是否已经在 GPU hot buffer 中,miss 的部分再从 CPU mirror 增量拷回 GPU。
3. V4 HiCache:让 Prefill 的前缀缓存从 GPU 一路延伸到 Storage
V4 HiCache 是 DeepSeek V4 在 prefill 阶段使用的分层 prefix cache。它把原本只能留在 GPU 的 prefix KV 扩展到 L2 Host 和 L3 Storage,并且要保证 Full、SWA 以及 DeepSeek V4 的 sidecar pools 一起移动。
这部分实现直接基于 python/sglang/srt/mem_cache/unified_radix_cache.py。
3.1 UnifiedRadixTree——一套接口,多种 KV 形态
UnifiedRadixTree 的定位很明确——统一 SGLang 的 PrefixCache 实现。它对 scheduler 暴露的仍然是 BasePrefixCache 风格接口:
match_prefix()
cache_finished_req()
cache_unfinished_req()
evict()
init_load_back()
变化发生在 tree 内部。传统 radix cache 的 node 主要保存一段 key 和一段 value;UnifiedRadixTree 的 node 额外保存了 component_data。每个 component 可以独立维护自己的 device value、host value、lock ref、host lock ref 和元数据。
当前主要 component 包括:
- FullComponent:管理基础 full logical value,也是大多数 prefix hit 的主坐标。
- SWAComponent:管理 sliding window KV,处理 SWA tombstone、full-to-SWA 翻译和窗口内恢复。
- MambaComponent:管理 Mamba state,处理状态类 cache 的 copy-on-write 语义。

图 5:UnifiedRadixTree 的可插拔缓存架构。
Scheduler 只调用统一的 PrefixCache API;模型差异通过 Full、SWA、Mamba 等 component 注入。DeepSeek V4 使用 FULL + SWA 作为 tree component,C4、C128、indexer 和 compress state 作为 sidecar pools,跟随主 anchor offload/load-back。
LRU 也按 component 拆开。Full、SWA、Mamba 可以有不同的驱逐优先级和锁范围;HiCache 打开后,还会有对应的 host LRU。这样主树只负责 radix 匹配、节点 split、insert、lock/refcount 和组件编排,具体的释放、恢复、备份逻辑交给 component hook。
对于 DeepSeek V4 来说,UnifiedRadixTree 只需要 FULL + SWA 两个 tree component。C4、C128、C4 indexer 和各类 compress state 不直接参与 prefix tree 匹配,它们作为 sidecar pools 挂在 Full 或 SWA 下面,在 offload/load-back 时跟随主 pool 一起搬运。
3.2 DeepSeek V4 如何基于 UnifiedRadixTree 实现多 Pool 的 Offload 管理

图 6:DeepSeek V4 HiCache Sider pools 跟随 anchor pool offload
V4 HiCache 的初始化路径如下:
UnifiedRadixCache.init_hicache()
-> attach_hybrid_pool_to_unified_cache()
-> build_deepseek_v4_hicache_stack()
-> HostPoolGroup + HybridCacheController
build_deepseek_v4_hicache_stack() 会为 DeepSeek V4 构造一组 host pools。基本结构是用 Full 和 SWA 作为 anchor,再把其他物理 pool 作为 sidecar 挂上去。
FULL anchor:
- KV
- C4 compressed KV
- C4 indexer KV
- C128 compressed KV
SWA anchor:
- SWA KV
- C4 compress state
- C4 indexer compress state
- C128 compress state
UnifiedRadixTree 不需要理解每个 sidecar pool 的物理 layout。它只构造 PoolTransfer:主 pool 要搬哪些 indices,sidecar pool 应该从哪个 anchor 推导 indices。数据移动由 HybridCacheController 负责,包括 host buffer 分配、device buffer 分配、D2H backup、H2D load-back,以及 L3 Storage 的 batch get/set。
回到 prefill 请求路径,V4 HiCache 的流程是:
prefill request
-> match_prefix(full logical tokens)
-> device hit: 直接复用 GPU prefix
-> host hit: init_load_back(best_match_node)
-> Full/SWA + sidecar pools H2D load-back
-> backend 根据 full indices 翻译 SWA/C4/C128/state
-> prefill 计算剩余未命中 token
L3 Storage 的位置也在这条链路里。Host L2 是更近的层;当前缀被写入 storage backend 后,后续请求可以通过 prefetch 把可能命中的 prefix 先拉回 Host,再由 load-back 恢复到 GPU。Mooncake 和 HF3FS 这类 backend 负责 Storage I/O,UnifiedRadixTree 仍然只维护 prefix match 和 node residency。
3.3 HiCache 实践——多轮对话吞吐提升 3 倍
HiCache 为 DeepSeek V4 提供了更大的 KVCache 存储空间,尤其适合多轮对话中大量复用历史前缀的场景。以下图中的 Multiturn 数据集为例,开启 L2 HiCache 后,相比 L1 Only,系统在保持较高前缀命中率和较低 TTFT 的同时,将 Input Throughput 提升到接近 3 倍。

图 7:Multi-turn Benchmark 结果
4. V4 HiSparse:Decode 阶段不再为冷 KV 买单
HiSparse 是 decode 阶段的 sparse attention 分层方案。它和 HiCache 使用的词汇有重叠——Host、GPU、load——但处理的问题完全不同。HiSparse 不依赖 UnifiedRadixTree 的 prefix hit,也不会通过 best_match_node 做 prefix load-back。
4.1 HiSparse——GPU 只留 hot buffer,miss 了再去拿
Sparse attention 的前提是:每一步只读取少量 KV。如果完整 KV 仍然常驻 GPU,那么计算变稀疏了,显存占用却没有同步下降。HiSparse 的设计就是把完整 KV mirror 放到 CPU pinned memory,在 GPU 上只保留一个较小的 hot buffer。
Decode 每步执行时,indexer 先给出本步需要访问的 top-k token。HiSparse kernel 随后检查这些 token 是否已经在 GPU hot buffer 中:
- 命中:直接读取 resident slot;
- 未命中:从 CPU host pool 拷到可驱逐的 GPU slot,并更新请求自己的 page table 或 slot table。

图 8: GPU 只保留小 hot buffer(4k/8k),CPU host pool 保存完整 KV mirror;miss 时再 swap-in。这是 decode-time sparse loading,不是 prefill prefix cache。
4.2 DeepSeek V4 + HiSparse 设计
DeepSeek V4 中,HiSparse 主要作用在 C4 compressed KV 上。SWA 只覆盖最近窗口,常驻 GPU 的成本相对可控;C128 仍按 dense history 读取;真正会随长上下文持续膨胀的是 C4 compressed history。因此,V4 HiSparse 的缓存布局可以概括为:
SWA: 留在 GPU,小而热
C128: 留在 GPU,dense 读取
C4: CPU full mirror + GPU hot buffer
C4 indexer / state: 按各自语义管理
在 P/D 分离部署中,Prefill 侧仍按 DeepSeek V4 的正常路径生成各类 KV。传到 Decode 侧时,C4 compressed KV 进入 Decode Host mirror,作为完整历史的 CPU 备份;SWA、C128、indexer 和 state 则进入 Decode GPU。这样 Decode Worker 不再为全部 C4 历史预留显存,只保留一个可替换的 C4 hot buffer。

图 9:DeepSeek V4 + HiSparse 的 P/D 传输与 decode 流程。
P 端将 C4 compressed KV 直接传到 Decode Host mirror,其他 V4 KV 进入 Decode GPU;D 端每步执行 C4 top-k、HiSparse swap-in 和 C4 sparse attention forward,并在生成新的 C4 token 后按需 D2H backup。
进入 decode 后的流程收敛成一个很短的循环。第一步,C4 indexer 根据当前 query 选出本步需要访问的 top-k compressed token position。第二步,HiSparseCoordinator.swap_in_selected_pages 检查这些 token 是否已经在 C4 hot buffer 中:命中时直接返回 GPU slot,未命中时从 Host mirror 拷入可驱逐 slot,并更新 LRU 与 token-to-slot 映射。第三步,DeepSeek V4 backend 用新的 device slot 覆盖 c4_sparse_page_indices,C4 sparse attention 只读取已经 resident 的 GPU KV。生成新 token 后,如果落在 C4 压缩边界上,再把对应 KV backup 到 Host mirror,保证 CPU 侧始终保有完整 C4 历史。
4.3 HiSparse 实践——显存节省转化为吞吐收益
HiSparse 的收益随并发和上下文长度变化明显。并发升高后,GPU 侧常驻 KV 的节省开始转化为大 Batch 高吞吐收益。

图 10:peak throughput for DeepSeek-V4-Flash on 2xB200, 200K-input / 20K-output, swa_full_tokens_ratio=0.001
另一个需要关注的指标是 miss count。hot buffer 太小或 LRU 策略不合适时,每步 top-k 会产生更多 host miss,导致 H2D 传输成为瓶颈。我们为每个 Req 在 Device 侧维护了 4K LRU Buffer,可显著降低每步 topk 的 miss tokens。

图 11:hot buffer 大小和 LRU 策略会直接影响 miss count。miss 不是系统噪声,而是 HiSparse 性能模型里必须单独管理的成本。
5. 总结
总得来说,DeepSeek V4 的分层缓存可以从三个层次来理解:
第一层是 Shadow Radix,解决的是“怎么描述”的问题。它把 prefix cache 统一在 full logical index 上,让 scheduler 和 radix tree 不需要直接管理 SWA、C4、C128、indexer 和 state pools。
第二层是 V4 HiCache,解决的是“Prefill 放不下”的问题。它基于 UnifiedRadixTree,把 Full/SWA 作为 prefix tree component,再通过 SidecarPool 把 DeepSeek V4 的多类物理 pool 一起 offload、load-back 和 prefetch。它服务 prefill,目标是提高长前缀 KV 的复用能力。
第三层是 V4 HiSparse,解决的是“Decode 占太满”的问题。它服务 decode,只针对 C4 sparse attention 做分层加载。CPU 保存完整 C4 mirror,GPU 只维护 per-request hot buffer,本步 top-k miss 才增量加载到 GPU。
这套架构在 Prefill 侧为多轮对话的 Input Throughput 提升接近 3 倍,长前缀命中率和 TTFT 均保持在健康水平;在 Decode 侧,HiSparse 在 2×B200、200K 输入的场景下,通过释放 C4 冷 KV 的显存占用,将 peak throughput 显著拉高——并发越大,收益越明显。
如果你正在部署 DeepSeek V4 的长上下文推理服务,尤其是面临多轮对话前缀复用或大并发 decode 的场景,欢迎尝试 SGLang + Tair KVCache 的组合。
参考资料
- SGLang DeepSeek-V4 Day-0 blog: https://www.lmsys.org/blog/2026-04-25-deepseek-v4/
- SGLang HiSparse blog: https://www.lmsys.org/blog/2026-04-10-sglang-hisparse/
来源:互联网
本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。