KV Cache Infrastructure

如何建立一个高速的 KV 缓存基础设施:要哪些组件、靠什么原理、拓扑怎么搭

高速 KV 缓存基础设施不是“搞一块大显存”这么简单。真正难的是把 prefix 复用paged / block 化分配跨请求共享分层存储调度器传输链路失效回收观测系统 串成一套能长期稳定跑的系统。这个页面讲的不是单个算子,而是整套基础设施怎么落地。

本质目标
少算 + 少搬 + 少等
系统核心
把 token 复用变成一等公民
最终效果
更低 TTFT / 更高吞吐 / 更稳成本

先定目标:高速 KV 缓存到底在解决什么

对大模型推理来说,最贵的不是“保存数据”,而是“重复做本来可以复用的 attention 计算”。KV 缓存基础设施的使命,就是把已经算过��� prefix/value 变成后续请求能直接命中的资产,而不是每次从头 prefill。
减少重复 prefill 提高 prefix 命中率 控制显存碎片 缩短 TTFT 提升 GPU 利用率 支撑多节点扩展

需要哪些核心组件

1. Token / Block 分配器

把连续的 KV 存储切成固定大小或半固定大小 block/page,避免每个请求拿一大段连续显存。

  • 页式分配,降低显存碎片
  • 按 block 建索引,支持重映射
  • 配合批量回收和惰性回收

2. Prefix 索引与查找层

把前缀转成可匹配的结构,不管是 radix tree、trie、chunk index 还是 hash 索引,目的都是快速判断“哪些 token 之前已经算过”。

  • 最长前缀匹配
  • 增量插入
  • 共享前缀引用计数

3. Scheduler / Admission 控制

缓存系统不只是存储层。调度器必须知道哪些请求能命中缓存、哪些值得等待合批、哪些需要抢占显存。

  • prefill / decode 分阶段调度
  • 命中优先级决策
  • 容量水位保护

4. 多级存储层

真正的基础设施通常不是只有 HBM。一层是 GPU HBM,二层可能是 host DRAM,三层可能是本地 NVMe 或远端对象缓存。

  • GPU 常驻热块
  • CPU 存温数据
  • 磁盘/远端存冷数据

5. 传输与预取链路

跨层缓存不是白送的。DMA、PCIe、NVLink、RDMA、异步预取、后台搬运,这些决定了命中是不是“真有收益”。

  • 异步 load / prefetch
  • 带宽预算与限流
  • 搬运与计算重叠

6. 回收、压缩与观测

缓存系统最后死在这里的最多。没有 eviction、引用计数、碎片治理、命中率观测,缓存迟早从加速器变成负债。

  • LRU/LFU/成本感知回收
  • OOM 保护与降级
  • hit rate / load latency / spill rate 指标

底层原理:为什么这些组件能提速

原理 解决的问题 收益 代价
Prefix reuse 重复请求每次都从头 prefill 直接减少 attention FLOPs 和 TTFT 需要复杂索引与失效管理
Paged / blocked KV 连续显存分配碎片严重 更稳定的内存管理和并发容量 需要额外 indptr / indices 映射
Multi-tier cache GPU HBM 太贵太小 扩大可复用上下文池 引入搬运延迟
Asynchronous prefetch 命中冷数据但取回太慢 减少 stall,让 GPU 不空等 需要预测和调度协同
Reference counting / pinning 共享前缀被误删 提升正确性和热数据稳定性 状态维护复杂
Cost-aware eviction 命中率高但搬入搬出抖动大 回收更接近真实收益最大化 策略和观测门槛更高
真正的关键不是“有没有缓存”,而是 缓存命中节省的计算 是否大于 缓存带来的索引、搬运、回收、同步成本

最常见的拓扑:单机热缓存、多机共享目录、分层冷存

                   ┌──────────────────────────────────────┐
                   │            Router / Gateway          │
                   │ prompt normalize + route by prefix   │
                   └──────────────────────────────────────┘
                                   │
                 ┌─────────────────┴─────────────────┐
                 │                                   │
       ┌──────────────────────┐           ┌──────────────────────┐
       │  Inference Node A    │           │  Inference Node B    │
       │ ┌──────────────────┐ │           │ ┌──────────────────┐ │
       │ │ GPU HBM hot KV   │ │           │ │ GPU HBM hot KV   │ │
       │ ├──────────────────┤ │           │ ├──────────────────┤ │
       │ │ CPU warm KV      │ │           │ │ CPU warm KV      │ │
       │ ├──────────────────┤ │           │ ├──────────────────┤ │
       │ │ local NVMe spill  │ │           │ │ local NVMe spill  │ │
       │ └──────────────────┘ │           │ └──────────────────┘ │
       └──────────┬───────────┘           └──────────┬───────────┘
                  │                                  │
                  └──────────────┬───────────────────┘
                                 │
                   ┌──────────────────────────────────────┐
                   │ Shared metadata / prefix directory   │
                   │ hash / trie / radix / ownership map  │
                   └──────────────────────────────────────┘

拓扑 A:单机内闭环

适合单机多卡或小规模集群。调度、索引、HBM/DRAM 分层都在一个节点内完成,链路短,调优简单。

  • 延迟最低
  • 实现最稳
  • 缓存复用范围仅限本机

拓扑 B:多机共享元数据

各推理节点本地存 KV,本地命中优先;只共享 prefix 元数据目录和 ownership 信息,避免把所有 KV 真正做成远程中心化存储。

  • 扩展性更强
  • 不会把所有流量压到中心缓存
  • 需要更聪明的路由与失效同步

不要一上来就做“全局远程 KV”

远程共享 KV 听起来很美:所有节点都能复用所有前缀。但现实是,KV 数据体量大、访问模式细碎、热度变化快。很多团队一开始就做中心化远程 KV,最后不是被网络打爆,就是被一致性和回收拖死。

更靠谱的演进顺序

  • 先做本地 HBM + DRAM 两级缓存
  • 再加 prefix 目录和路由亲和
  • 最后再考虑跨机 materialized KV 迁移

原因

  • 绝大部分收益先来自本地 prefix 命中
  • 网络 hop 是硬成本,不会凭空消失
  • 先把命中、回收、碎片治理做好再扩展

请求流转时序:一条命中的请求到底怎么跑

Client Request
    │
    ▼
[Prompt normalize]
    │  tokenize / trim / template canonicalization
    ▼
[Prefix lookup]
    │  longest-prefix match -> locate cache entry
    ├──────── miss ────────► full prefill on GPU
    │
    └──────── hit ─────────► map token blocks / fetch warm blocks
                              │
                              ▼
                       [Scheduler admission]
                              │ merge with running decode batch if possible
                              ▼
                       [GPU execute remaining prefill]
                              │
                              ▼
                       [Decode loop]
                              │
                              ▼
                       [Update index + refcount + heat]
                              │
                              ▼
                       [Evict / pin / spill if needed]

一个靠谱的组件边界长什么样

职责 不要做什么
Router 规范化请求、做亲和路由、尽量把相似 prefix 打到同节点 不要自己维护 KV 细粒度生命周期
Prefix Index 维护 prefix → block list / ownership / heat 不要直接碰 GPU 执行细节
Memory Manager 管理 HBM/DRAM/NVMe block、引用计数、回收策略 不要决定业务优先级
Scheduler 决定 admission、batch 组成、prefetch 时机 不要把索引结构硬编码死
Transfer Engine 执行异步搬运和预取,重叠通信与计算 不要自己拍脑袋回收缓存
Observability 输出 hit rate、spill rate、fetch latency、fragmentation 不要只看平均值

设计里的关键取舍

固定 block 大小 vs 可变 block

固定 block 更利于实现和管理;可变 block 在理论上能减少浪费,但 metadata 和重组复杂度更高。多数工程系统会先用固定 block,再局部加优化。

精确匹配 vs 模糊共享

严格 prefix 匹配最稳;做相似 prompt 的模糊共享往往收益不如风险大,因为位置、模板、special token 差一点都可能让缓存失效。

中心目录 vs 去中心目录

中心目录简单但容易成为瓶颈;完全去中心又难协调。现实里经常是分片目录 + 局部 ownership + 路由亲和。

回收看“最近”还是看“成本”

单纯 LRU 容易错杀刚好贵的 prefix。更好的策略是结合热度、重算成本、传输成本、命中概率做综合回收。

高速的前提:你的 prompt 体系得可规范化

如果上游 prompt 每次都多一个随机字段、时间戳、顺序噪音、不可控系统提示,那你再强的 KV cache infra 也很难有高命中率。缓存基础设施和 prompt canonicalization 是绑在一起的。

该做的

  • 统一模板和 separator
  • 把高频 system prompt 固化
  • 把无关动态字段后移
  • 做 tokenize 之前的 canonicalization

别做的

  • 每个请求塞唯一 trace id 到 prefix
  • 让多条同构请求拥有不同模板空格/换行
  • 把工具结果历史无限拼进同一前缀
  • 指望缓存层替你纠正 prompt 设计问题

缓存基础设施最容易挂掉的地方

症状                        根因
────────────────────────    ─────────────────────────────────────
命中率看起来高              但搬运延迟太大,实际 TTFT 没降
显存经常爆                  block 回收不及时 / pin 太多 / 批量回收缺失
吞吐抖动                    prefetch 与 decode 抢带宽 / admission 不稳
跨节点命中率低              路由没做 prefix affinity
缓存越大越慢                metadata 过重 / 查找成本过高 / 冷数据太多
��统很复杂但收益一般        上游 prompt 根本不规范、复用率不够

推荐的落地路线

阶段 1:单机高质量缓存

  • paged KV allocator
  • prefix index
  • 引用计数 + eviction
  • 基础 hit / miss 指标

阶段 2:调度协同

  • 命中优先 admission
  • prefetch 与 batch 构造结合
  • 热数据 pinning
  • 容量水位和降级路径

阶段 3:集群化

  • prefix-aware routing
  • 共享元数据目录
  • 跨机 warmup / transfer
  • 基于收益的全局回收策略

适合什么团队 / 不适合什么团队

适合

  • 有明显重复前缀流量的 LLM 服务
  • 长 system prompt、长上下文、RAG 模板固定的场景
  • 在线推理成本高、TTFT 敏感的团队
  • 已经有基本调度和显存管理能力的 infra 团队

不适合

  • 请求高度随机、前缀几乎不复用
  • 业务还在 prompt 形态剧烈变化期
  • 团队还没有观测、回收、调度的工程基础
  • 想一步到位做全球共享远程 KV,但没有高带宽低时延网络预算