vLLM 与 SGLang KV Cache 底层实现机制深度调研报告

基于 vLLM(vllm-project/vllm)与 SGLang(sgl-project/sglang)main 分支源码,2026-08-21。


一、底层 KV Cache 实现机制(基于 main 分支源码)

1. vLLM:PagedAttention + 哈希链前缀缓存

分层结构 :KVCacheManager (vllm/v1/core/kv_cache_manager.py) → KVCacheCoordinator (kv_cache_coordinator.py,按 KV 类型分组:全注意力/滑窗/Mamba) → 每组一个 SingleTypeKVCacheManager → 共享一个 BlockPool (vllm/v1/core/block_pool.py)。

核心数据结构(直接读源码验证):

  • BlockPool.blocks: 全量 KVCacheBlock 数组;free_block_queue: 空闲块双向链表(同时充当 LRU 驱逐队列------被缓存但空闲的块留在队尾作驱逐候选)。
  • BlockHashToBlockMap: dict[BlockHashWithGroupId, KVCacheBlock | dict[int, KVCacheBlock]],hash→物理块索引。同 hash 多块时退化为 dict(源码注释明确说明不做去重,以保证 block table append-only)。
  • 块哈希是链式的 :第 i 块的 hash = f(父块 hash, 本块 16 个 token id, extra_keys),见 kv_cache_utils.py 的 hash_block_tokens/resolve_block_hashes。这保证前缀任何位置不同则后续全部 miss。
  • 命中流程:请求创建时预计算全序列 block_hashes → get_computed_blocks() 逐 hash 查 cached_block_hash_to_block → 命中块 ref_cnt++(touch),只 prefill 未命中尾部;新满块经 cache_full_blocks() 注册进哈希索引。

物理层 :gpu_model_runner._allocate_kv_cache_tensors() 用 torch.zeros(int8) 分配一整块 buffer(按 block_stride 打包多层别名同一 backing),再 reshape 成各 attention backend 的 KV shape;kernel 通过 slot_mapping 散射写入、block_table 分页寻址(vllm/v1/attention/backends/flash_attn.py)。

调度与抢占 :V1 抢占只有 recompute 模式 (无 CPU swap)------Scheduler._preempt_request() 直接把 num_computed_tokens 清零、释放块、重新排队重算。长 prompt 被抢占 = 全部 prefill 重来,这是 agent 场景最贵的失败模式。

2. SGLang:RadixAttention 前缀树 + 两级内存池

Radix Tree (python/sglang/srt/mem_cache/radix_cache.py,已验证):

  • TreeNode: children: defaultdict、key: RadixKey(token 序列 + extra_key LoRA 隔离 + cache_salt)、value(KV 物理页索引 tensor)、lock_ref 引用计数、last_access_time、host_value(host 层副本)。
  • match_prefix(): 从 root 下行匹配;RadixKey.match() 用指数搜索+二分 找首个分叉 token(避免逐 token Python 循环);命中落在节点中间时 _split_node 切分;结果按 page_size 对齐截断。
  • evict(): 只驱逐叶子(evictable_leaves 堆),默认按 last_access_time LRU(策略工厂支持 lru/lfu/fifo/slru/priority);父节点变叶子后入堆继续驱逐;lock_ref > 0 的节点(被 in-flight 请求引用)受保护。
  • 与 vLLM 的本质区别:vLLM 是「定长块 + 平铺哈希表」,SGLang 是「变长节点的前缀树」------树天然表达前缀包含关系,且支持 token 级 page_size=1 的细粒度复用。

物理池 (mem_cache/memory_pool.py + allocator/):

  • ReqToTokenPool: 请求→token 物理位置的页表;MHATokenToKVPool/MLATokenToKVPool 等:真正的 KV tensor(NHD/page-major 布局;MLA 存压缩 latent)。
  • PagedTokenToKVPoolAllocator(page_size>1 时):alloc/free 用 CUDA kernel 批量操作 free page 列表。

HiRadixCache 层次缓存 (hiradix_cache.py):在 GPU (L1) 之上叠 host 内存 (L2) 和外部存储 (L3),write_through/write_back 写策略 + prefetch;L3 后端工厂(storage/backend_factory.py)注册了 mooncake / hf3fs / nixl / aibrix / file / shm 等------即 KV 可以落到跨节点分布式存储。

graph TB subgraph vLLM V1 A[KVCacheManager] --> B[KVCacheCoordinator<br/>full-attn / SWA / Mamba 分组] B --> C[BlockPool<br/>KVCacheBlock[] + free 双向链表 LRU] C --> D[BlockHashToBlockMap<br/>链式哈希 → 物理块] C --> E[int8 大buffer reshape<br/>slot_mapping + block_table] end subgraph SGLang F[RadixCache / HiRadixCache] --> G[RadixTree<br/>TreeNode + lock_ref] G --> H[ReqToTokenPool 页表] G --> I[MHA/MLA TokenToKVPool<br/>+ PagedAllocator] F -.L2/L3.-> J[Host mem / Mooncake / 3FS / NIXL] end

二、问题一:agent 长时程任务下如何高吞吐

按「省显存 → 提复用 → 架构级扩展」三档,均为两引擎已落地的机制:

手段 原理 vLLM 落地 SGLang 落地
Prefix caching 复用共享前缀跳过重复 prefill 默认开启,链式哈希 Radix 树,勿 --disable-radix-cache
KV 量化 fp8/nvfp4 直接减半/减 75% 占用 --kv-cache-dtype fp8(Blackwell 可 nvfp4) 同名参数,MLA 有独立 fp8 路径
Chunked prefill 长 prompt 切块与 decode 混排,削激活峰值 默认开,max_num_batched_tokens --chunked-prefill-size
SWA 稀疏缓存 滑窗层只留窗口内 KV,窗外即时释放 hybrid cache manager 区分 full/SWA 组 SWAChunkCache + free_swa_out_of_window_slots
KV offloading 冷 KV 异步搬到 CPU/SSD/远端 OffloadingConnector(CPU 单层 / Tiering 多级 FS/OBJ/P2P,lru/arc 策略) HiRadixCache(--hicache-size + L3 backend)
PD 分离 prefill/decode 各自独立 GPU 池,RDMA 传 KV MooncakeConnector / NixlConnector(Pull/Push) --disaggregation-mode + mooncake/nixl 后端
准入控制 watermark 预留 + max_num_seqs + 抢占兜底 watermark、_preempt_request(recompute) retract_decode

agent 场景特有的三个杠杆(往往比引擎调参收益更大):

  1. Prompt 结构设计 :把稳定的 system prompt、工具 schema 放在最前面,每轮变化的工具结果放尾部------前缀哈希/radix 匹配要求逐字节一致,前缀处任何一个时间戳都会让命中点后移。
  2. Session 粘性路由:同一会话路由到同一实例,最大化本地缓存命中(配合下方问题二)。
  3. Context 压缩:LLMLingua 类工具在 prefill 前裁剪 prompt;LMCache 的 CacheBlend 支持非前缀位置 KV 复用+局部重算。

组合原则:先提命中率(前缀缓存+路由+prompt 结构)省 prefill → 再量化省单位占用 → 再 offloading 省总量 → 最后 PD/L3 做横向扩展。业界参照:Mooncake(Kimi,arXiv:2407.00079,KVCache-centric 分离架构)、LMCache(arXiv:2510.09665)、NVIDIA Dynamo+NIXL。


三、问题二:KV Cache 是否只能存本机、必须粘性路由?

这个说法一半过时、一半仍是工程现实。

过时的部分------跨节点分布式 KV 已经是两个引擎的一等能力:

路径 代表实现 成熟度
远端 KV 池(L3) SGLang HiCache + Mooncake Store/3FS/NIXL/AIBrix 后端;vLLM OffloadingConnector Tiering(FS/OBJ/P2P)、LMCache(CPU/SSD/Redis/Mooncake) 生产可用,多实例共享同一份前缀 KV,无需粘性路由也能命中
PD 间 KV 直传 vLLM MooncakeConnector/NixlPushConnector(RDMA 直写对端 GPU 显存);SGLang disaggregation/(bootstrap handshake + mooncake/nixl conn) 大规模生产验证(Mooncake 论文即 Kimi 生产架构)
KV 事件发布 vLLM kv_events.py(BlockStored/BlockRemoved,ZMQ pub-sub),供外部 gateway 建全局 KV 索引 较新,生态建设中

另外纠正一个隐含前提:即便单机内,TP 多卡时 KV 本来就是按 head 切分存在多卡上的------"单节点"本身已是分布式存储。

仍然成立的部分 ------粘性路由依然是主流默认,原因是经济性而非技术不可行:

  • 跨节点取 KV 的传输成本(即使 RDMA,GB 级 KV 也要毫秒~十毫秒级)vs 就地重算 prefill 的成本,只有命中率足够高时传输才划算;
  • 本地 radix/prefix 缓存命中是零成本、零延迟的;
  • 所以生产栈(NVIDIA Dynamo、vLLM Production Stack、SGLang Router)的标准做法是 cache-aware routing:先按前缀哈希做亲和性调度把命中率做满,分布式 KV 作为溢出层处理"亲和节点已被驱逐/重启"的长尾。

选型建议:

  • 单集群、会话可路由 → 粘性/cache-aware 路由 + 本地缓存即可,不必上分布式 KV;
  • 多实例需要共享大 system prompt/RAG 语料、或实例弹性伸缩导致亲和失效频繁 → 上 LMCache 或 SGLang HiCache L3(Mooncake 后端);
  • 已有 RDMA 网络、追求极致吞吐 → PD 分离 + NIXL/Mooncake 直传。

来源 :vLLM 源码 vllm/v1/core/{block_pool,kv_cache_manager,kv_cache_utils}.py、vllm/distributed/kv_transfer/kv_connector/v1/、docs/features/{mooncake_connector_usage.md,kv_offloading_usage.md};SGLang 源码 python/sglang/srt/mem_cache/{radix_cache,hiradix_cache,memory_pool}.py、python/sglang/srt/disaggregation/、docs/docs/advanced_features/{hicache_design,pd_disaggregation}.mdx;业界资料 Mooncake arXiv:2407.00079、LMCache arXiv:2510.09665、kvcache-ai/Mooncake、LMCache、NVIDIA Dynamo 文档。

相关推荐
打工仔折腾 AI12 小时前
从 Demo 到生产级 Agent:8 个关键设计机制与 Python 实现拆解
java·jvm·人工智能·后端·python·langchain·ai agent 实战
架构技术专栏13 小时前
交叉熵:AI 怎样给概率预测打分
后端
前端snow13 小时前
ai agent --- 文件存储
前端
Frag0ut13 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
CHEEVEN_QY13 小时前
液冷板热阻计算与流阻优化的实战方法
人工智能·算法·机器学习
C++ 老炮儿的技术栈14 小时前
不一样的数值交换
数据结构·c++·人工智能·算法·c·csdn开发云
IT_陈寒14 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技14 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
hahaha601615 小时前
Shades-of-Gray (SoG) 算法--白平衡算法
人工智能·嵌入式硬件·算法·计算机视觉
zeng不错15 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端