跳转至

运行时架构

KVCache 在推理引擎中的位置

一个典型的 LLM 推理引擎分为以下几层:

┌─────────────────────────────────────┐
│             API Server              │  ← 接收请求,管理 session
├─────────────────────────────────────┤
│             Scheduler               │  ← 决定哪些请求进入当前 batch
├─────────────────────────────────────┤
│          Block Manager              │  ← 管理 KVCache 的物理显存块
├─────────────────────────────────────┤
│         Model Executor              │  ← 执行 Prefill/Decode kernel
├─────────────────────────────────────┤
│      GPU HBM (KVCache Storage)      │  ← 物理存储 K/V 张量
└─────────────────────────────────────┘

KVCache 横跨多个层次:它的分配由 Block Manager 负责,调度决策(哪些请求能用多少 KV 空间)由 Scheduler 决定,实际读写发生在 Model Executor 内的 Attention kernel 中。

核心概念

Sequence(序列)

一个请求对应一个 Sequence(或多个,如 beam search)。Sequence 的生命周期: 1. Waiting:请求到达,尚未进入 GPU 2. Prefill:Prompt 处理中,KVCache 正在写入 3. Decoding:逐 token 生成,KVCache 持续追加 4. Finished:生成结束或被中止,KVCache 可以释放

Block / Page

Block(也称 Page)是 KVCache 的分配单位,而不是单个 token。一个 Block 存储固定数量(block_size)的 token 的 KV 数据。

Block 的意义:以 Block 为单位分配,而不是按精确 token 数,避免了每步解码都需要重新分配显存的开销,也为 Prefix Cache 的粒度提供了基础。

典型 block_size 选择:
- vLLM 默认:16 tokens/block
- SGLang 默认:16 tokens/block(部分场景可配置更大)

Slot

Slot 是 Block 内的最小分配单位,对应一个 token 的 K/V 存储位置。slot_id = block_id * block_size + token_offset_in_block。

Block Table

每个 Sequence 维护一张 Block Table,记录它的每个逻辑 Block 映射到哪个物理 Block。Block Table 由 Block Manager 管理,在 kernel 执行时作为索引传入 GPU。

逻辑 Block 序号:   0     1     2     3
物理 Block 地址:  [47]  [23]  [81]  [56]

这一间接层是实现 Paged KV 和 Prefix Cache 的关键机制。

Block Manager

Block Manager 是推理引擎的显存分配器,负责:

  1. 初始化:将所有可用 HBM 按 block_size 划分为固定大小的物理 Block 池
  2. 分配:当 Sequence 需要新 Block 时,从空闲池中取出物理 Block,更新 Block Table
  3. 释放:Sequence 完成时,将其使用的物理 Block 归还空闲池
  4. 复制(Copy-on-Write):用于 beam search 或 Prefix Cache 场景下的 Block 共享与分叉
  5. Eviction:当显存不足时,决定驱逐哪些 Block(通常是优先驱逐最长时间未使用的)

空闲池状态

total_blocks = gpu_kvcache_memory / (block_size × per_token_kv_bytes)
free_blocks = total_blocks - allocated_blocks

Scheduler 在构建每个 batch 前会查询 Block Manager 的空闲状态,确保 batch 内所有请求的 KVCache 需求可以被满足。

Scheduler 与 KVCache 的交互

Scheduler 决定哪些请求可以进入当前 batch,KVCache 可用量是关键约束之一。

典型调度流程:

  1. 估算当前等待队列中每个请求的 KVCache 需求(已有 token 数 + 预期生成长度)
  2. 根据 Block Manager 报告的空闲 Block 数,选择可以容纳的请求集合
  3. 如果 GPU KVCache 耗尽,触发抢占(Preemption):
  4. Swap:将部分 Sequence 的 KVCache 换出到 CPU DRAM
  5. Recompute:丢弃部分 Sequence 的 KVCache,之后重新 Prefill

抢占策略直接影响系统在高负载下的延迟尾部和吞吐。

连续内存 vs 分页管理

连续内存分配(早期方案)

早期推理系统对每个 Sequence 预分配连续显存(按最大序列长度),存在严重问题:

  • 内部碎片:预分配长度 > 实际生成长度,剩余空间浪费
  • 外部碎片:短序列释放后产生碎片,无法被较长序列利用
  • 低并发:每个 Sequence 持有大块连续显存,批量大小严重受限

分页管理(PagedAttention)

将 KVCache 划分为固定大小的 Block(类比 OS 分页),Sequence 按需申请 Block,Block 可以不连续。

  • 无外部碎片:物理 Block 池统一管理,按块复用
  • 内部碎片最小化:最后一个 Block 可能有未使用的 Slot,但总碎片 ≤ (block_size - 1) tokens/sequence
  • 高并发:每个 Sequence 按实际使用量占用空间,同等显存可服务更多并发请求

详见 Paged KV 章节。

Fragmentation 与 Reuse

即使在分页管理下,仍然存在一些次要问题:

  • 内部碎片:每个 Sequence 最后一个 Block 可能未填满
  • Block 复用:Prefix Cache 允许多个 Sequence 共享同一物理 Block(只读场景),需要引用计数管理
  • Eviction 策略:当显存不足时,被驱逐的 Block 如果之后又需要,必须重算(recompute)或从 CPU 换入(swap)

这些问题是推理引擎 Block Manager 工程设计的核心复杂性来源。

类型体系:从一个 Block Manager 到多种 KV 规格

2026 年之后的主流推理引擎不再只管理"标准 MHA/GQA KV"。vLLM v1 的 KVCacheSpec 把 FullAttention、MLA、SlidingWindow、ChunkedLocal、CrossAttention、Mamba state 等规格统一到三个问题:一个 page 占多少字节、单请求最大占多少显存、最多 admission 多少 block。这样调度器可以在 admit 请求前按类型计算最坏显存需求,而不是只用上下文长度做粗估。

维度 典型差异 对运行时的影响
page_size_bytes MHA/GQA 与 MLA 的 per-block 字节差异可达数倍 BlockPool 容量、传输粒度和 offload 带宽估算都要类型感知
growth mode full attention 线性增长,SWA 有界增长,Mamba 恒定状态 Scheduler 不能把所有模型都按 \(O(n)\) KV 增长处理
group layout 混合模型可能同时含 attention 与 state-space group 存储池需要按 group 分配,而不是一池到底

SGLang 的存储池体系更进一步把 MHA/GQA、MLA、DSA、DeepSeek-V4、SWA、FP4、Host KV 分成独立 pool class。DeepSeek-V4 的 pool 同时维护 SWA、C4、C128 三类压缩层和辅助 ring/state buffer;这说明"一个 token 对应一份物理 KV"已经不再成立。

来源:主站 field-note vLLM KV Cache 类型体系拆解,主站 field-note SGLang KV Cache 存储池架构

KVBM:Block Manager 的外置化

NVIDIA Dynamo KVBM 将 KV 管理拆成 runtime 接口、逻辑生命周期和物理数据面三层。它的意义不是替代 PagedAttention,而是把引擎内部的 block manager 外置成可跨 engine、跨 replica、跨存储层级协调的内存子系统。

层次 负责内容 关键边界
Runtime 接口 engine 提交 block allocate / append / release / transfer 请求 保持 vLLM/SGLang/TRT-LLM 等 runtime 可接入
逻辑生命周期 强引用、弱引用、可取消 transfer、block 可见性 决定一个 block 何时能被复用、迁移、驱逐
物理数据面 GPU/CPU/NVMe/remote storage 的搬运与格式转换 通常交给 NIXL、Mooncake、LMCache 等传输/存储后端执行

这类外置化会改变调度接口:Scheduler 需要知道的不只是"还有多少 free block",还包括 block 在哪一层、是否正在 transfer、是否可取消、是否值得预取。相关数据面见 存储层级 与 PD 分离。

来源:主站 field-note NVIDIA Dynamo KVBM 源码笔记

关联章节

版本历史

版本 日期 说明
v0.2 2026-06-02 新增 KVCacheSpec / SGLang 多池类型体系与 Dynamo KVBM 外置 block manager 视角
v0.1 2026-05-14 框架搭建