详细解释
**KV Cache Eviction(KV 缓存淘汰 / KV Cache 管理策略)**一句话:一张 A100-80G 总共就 80GB HBM,模型权重占了 70B BF16 的 140G(需要多卡)或者 7B FP8 的 7GB,剩下的空间用来放所有并发请求的 KV Cache;如果 100 个并发请求的 KV Cache 加起来超过了剩余显存,你作为调度器必须扔掉一些「相对没用的」KV Cache 页来给新请求腾空间,扔什么、什么时候扔、扔多少——这套规则就是 KV Cache 淘汰策略。 没有淘汰策略的原生推理引擎,KV Cache 超了就直接 OOM Crash,用户看到 500;好的淘汰策略配合 vLLM PagedAttention 能让单 GPU 的并发数(TPS 上限)提升 2 至 4 倍,OOM 故障率从 1% 降到 0.01%。
KV Cache 淘汰的底层前提是 PagedAttention(vLLM 2023 年提出的技术)——它把 KV Cache 切成固定大小的物理页(类似 OS 的内存页),用页表把「逻辑上连续的 Token 序列」和「物理上零散的 KV 页」映射起来;只有在分页机制的前提下,才能像 OS 做虚拟内存一样去做「LRU 页淘汰、页换入换出、共享物理页」这些事情,没有分页的话 KV 是一块连续大内存,根本没法做细粒度淘汰,只能整请求 kill。
唯元智创 自己的推理集群采用「四分层三级淘汰策略」:20% HBM 固定放钉住的前缀(Pinned Prefix,永远不淘汰)、40% 放活跃请求的 KV Cache、30% 放滑动窗口式的历史上下文窗口(超过 32K 就从最老的页滚着扔)、剩下 10% 做缓冲;任何新请求来时按优先级找可释放的页,OOM 概率百万分之一以下,单 4090 跑 7B FP8 模型稳定 120 并发不崩。
六大主流 KV Cache 淘汰策略对比(2025 年选型)
| 策略 | 做了什么 | 适合场景 | 实现复杂度 | 并发上限提升倍率 | 典型引擎内置支持 |
|---|---|---|---|---|---|
| ① 全 Kill(没有淘汰,超了直接 OOM) | 任何请求进来有空间就放,没空间新请求直接返回 OOM 500 | 极低并发的原型 / 个人部署(一张 4090 跑 5 个并发以内) | 极低,没有代码 | ×1(基线) | HuggingFace generate 默认就是这个 |
| ② 整请求级 FIFO/LRU(整请求整体扔掉) | 按请求整个为粒度,先进先出 / 最少最近使用,整个请求的所有 KV 页一起扔 | 低并发 + 请求长度都差不多的简单场景 | 低 | ×1.2–1.5 | vLLM 早期版本 |
| ③ 页级 LRU(单页粒度最近最少用) | PagedAttention 基础上,每个 KV 页独立 LRU,最久没被访问的单页先扔 | 大多数通用推理场景,长短请求混合 | 中 | ×2–3 | vLLM 新版、SGLang 默认 |
| ④ 分层优先级(Pinned / LRU / Sliding-Window 三区) | 三区独立管理:Pinned 永久不扔、LRU 普通热页、SW 滚着扔超过窗口的老页 | 高并发生产服务,有固定常用前缀场景 | 高 | ×3–4.5 | SGLang 2025 / 唯元内部推理引擎 |
| ⑤ 重要性打分 + 启发式淘汰 | 每个 KV 页按「最近 Attention Score + 所在层深度 + 是前缀还是生成 Token」算一个重要性分,先扔分最低的 | 超长上下文 100K+、推理质量对 KV 丢页敏感的场景 | 极高 | ×3.5–5 | 学术前沿 + 超大上下文模型(Kimi 1M 上下文) |
| ⑥ 分层内存(HBM + CPU DDR + NVMe)三级换页 | GPU HBM 存热页、CPU 内存存温页、本地 NVMe 存冷页,类似 OS 的虚拟内存 swap | 超长上下文 1M Token 场景,单卡放不下整份 KV | 极高(驱动/通信复杂) | ×5–10 | SGLang / TensorRT-LLM 企业版 |
落地 KV 淘汰的 6 条工程纪律
- 永远不要让「正在流式输出中的活跃请求」的 KV 页被淘汰——用户正打字的中途把它的 KV 扔了,流式输出立刻中断卡死或胡言乱语;活跃请求的 KV 页优先级最高,只有当整个 GPU 内存 100% 满并且没有可扔的非活跃页时,才允许先 kill 掉一个优先级最低的活跃请求再腾空间,而且要返回标准 429 错误通知用户重试。
- Sliding Window Attention 模型的淘汰要跟注意力窗口对齐,不要瞎扔窗口中间的 KV 页——比如模型只支持最近 32K 滑动窗口,你就应该把 32K 之前最老的页按顺序滚着扔;如果扔中间的某一段(比如窗口里 16K 处的页),Attention 计算会直接对不齐产生大量幻觉,输出完全不可用。
- Pinned 的前缀页一定要有硬上限,不能让钉住的内容吃掉 80% HBM——实际设置最多不超过 20-25% 的总 KV 可用空间;如果你的热门前缀有几百条,不要全钉住,挑最近 7 天 Top 20 钉住就行,剩下的走 LRU 温区就够了,别为了 1% 的命中率提升牺牲 50% 的并发上限。
- 做指标监控:命中率、淘汰频率、每类页的空间占比、被 Kill 的活跃请求数量——理想的健康值:(a)页级命中率 > 99%(大部分访问的页已经在内存里);(b)每秒淘汰页次数 < 总页数的 1%(淘汰不抖动);(c)活跃请求占用率 30-70%(有余量应对突发);(d)因为内存满被 Kill 的活跃请求每小时 < 1 次 / GPU。任何一个指标突破健康区立刻报警。
- 预热 + 冷启动策略:重启后的前 5 分钟,LRU 是空的,这时候不要接高并发——先用一批预定义的 dummy 请求把 Pinned 前缀页加载好、把常用工具 Schema 的 KV 页热好,再接真实流量;否则冷启动的几百毫秒-几秒高延迟窗口会让用户直接投诉。
- 多租户场景一定要做 KV Cache 按租户隔离 + 配额限制——不然一个大客户的 1 万并发长上下文请求,把 KV Cache 全占了,其他 100 个小客户全部 OOM 报错,这是 SaaS 级事故;每个租户设置最大 KV Cache 配额(比如大客户最多占 30%、中小客户各 0.5%),超过配额的请求走 429,禁止跨租户抢资源。Rate Limit 里的多租户配额策略可以直接平移到这里。