分层 KV Cache:从 GPU 命中到外部存储复用
用容量、搬运和生命周期解释 GPU—CPU—远端 KV 分层,固定 LMCache 0.5.5 的 MP、lazy offload 与锁定合同
本文目录
Prefix Cache 的生命周期不必结束于 HBM 驱逐。分层 KV 把可复用状态保留在 CPU 内存、另一台机器或存储设备里,在下一次请求到来时决定加载还是重算。它增加的是可复用容量,同时引入搬运、发现、锁定和回收的成本。
先用 KV Cache 建立分页与复用语义,再用 KV Hit Ratio 模型 区分命中面积与端到端收益。本页的版本证据固定为 LMCache 0.5.5 05a013b29da78cf2321b9b46ec5039dde2fb0bb0;实现细节以其 MP 文档和 design 源码说明为边界,没有独立 GPU 或 RDMA 实测。
- 一句话:分层 KV 用更大的外部容量换取重算机会,但一次可发现的命中必须能在使用前完整、兼容地加载。
- 三个判断:区分 GPU hit 与 external hit;比较关键路径上的加载时间与被省掉的计算;锁定生命周期要覆盖发现到消费完成。
- 核心模型:外部复用的净收益约为 ,不能直接把命中率当提速比例。
- 边界:backend、connector、模型状态与版本决定可用能力;分层复用不自动提供当前请求的 P/D 交接,也不保证质量变化类优化的等价性。
1. 从“命中”拆出三个问题
一个请求找到相同 token prefix,还需回答:语义是否一致、状态是否仍在、加载是否划算。
| 层次 | 要检查的合同 | 常见失败 |
|---|---|---|
| 语义身份 | 模型/adapter、token IDs、位置与影响 forward 的配置一致 | 相同字符串、不同 tokenizer 或 adapter |
| 存储身份 | KV dtype、scale、layer/block layout、rank 分片可被当前消费者解释 | 两端 TP 或 kernel layout 不同,却按裸字节导入 |
| 驻留与生命周期 | 对象在发现后被锁定,直到读取完成;GPU blocks 未被重用 | 查到 key 后对象被驱逐,或异步 store 读到旧 block |
| 性能选择 | 加载的暴露时间与控制成本小于重算收益 | 高命中率但小块搬运、排队与网络竞争拖慢 TTFT |
具体 cache key 编码由实现决定,表格是正确性合同,不声称每个 backend 自动校验所有字段。跨模型共享动态 KV 也不是 Engram 静态权重的 同机 DP 共享。
2. 分层的是容量,也分层了速度
flowchart TB
R[请求的 prefix] --> G{本地 GPU 命中?}
G -->|是| C[继续计算 suffix]
G -->|否| E{外部 KV 可用且兼容?}
E -->|是| L[锁定、加载、恢复状态]
L --> C
E -->|否| P[重算 prefix]
P --> C
C -. 可复用状态 offload .-> H[CPU / peer / 存储 backend]
这里的 HBM、host RAM、远端内存、SSD/对象存储是系统层次。LMCache MP 的 L1/L2 是该产品的命名,不能机械套成 CPU L1 cache 与 GPU HBM:MP L1 由独立 server 管理,L2 才由配置的存储 backend 扩展。
LMCache 0.5.5 的 MP 支持文档列出 local filesystem、raw block、DAX、NIXL、Mooncake、S3 等后端。列在支持表不代表默认全部启用,也不代表每条链路具有同样的 prefetch、P2P、锁或恢复能力。部署必须固定 server 模式、connector、backend 配置和传输路径。KVBM、HiCache 等其他体系也应单独核对版本,不能凭“分层 KV”名称套用 LMCache 参数。
2.1 容量先按模型、层与 rank 落账
普通 attention 的未压缩 KV payload 可用
估算,其中 是每元素字节数。加载量只计被复用的 tokens,并按实际 rank 分片、block rounding、scale 与 metadata 修正;MLA、压缩 attention、SWA 和 recurrent state 需换成各自状态公式。
因此 DeepSeek V4.1 Runtime 的 packed record 大小不能直接充当所有模型的每 token 网络 payload。压缩记录、滑窗及边界恢复状态的生命周期不同,connector 是否完整支持需要单独证明。
2.2 用有效带宽判断加载下限
这是单条串行路径的下限模型。多跳的 CPU、PCIe、NIC 和 HBM 应按瓶颈及流水重叠计算,不能用 NIC 标称速率代替测得的有效带宽,也不能把已重叠的各层时长相加。
仅作算例:加载 4 GiB,若有效带宽是 25 GiB/s,纯 payload 下限为 160 ms,还没计发现、排队或恢复。若相同 prefix 重算只需 100 ms,外部命中不会天然降低该请求 TTFT。若它省掉 800 ms 计算且只有 60 ms 加载暴露在关键路径,则可能值得复用;两种情形都不是设备实测。
2.3 缓存已 offload,Router 未必看得见
Dynamo 1.5.1 的 offloading support matrix 进一步区分“engine 能存到某层”与“router 能按该层命中加权”。这决定请求会不会被送到实际拥有外部 KV 的 worker。
| Backend 路径 | 固定文档的版本门槛与可见性 | 边界 |
|---|---|---|
vLLM native OffloadingConnector | vLLM ≥ 0.24.0、Dynamo ≥ 1.3.0;aggregated CPU RAM 可按 tier 路由 | Disk 的 STORAGE 映射尚未完全验证;remote/shared-pool 事件索引仍在建设 |
| SGLang HiCache | SGLang ≥ 0.5.11、Dynamo ≥ 1.2,GPU/host events 可区分 | Mooncake shared pool 路径要求 SGLang ≥ 0.5.13,并显式配置 shared cache |
| TensorRT-LLM native host cache | Dynamo ≥ 1.3.0 的 event flag;GPU + RAM 合并可见 | Router 无法区分实际驻留 tier,host/disk 的独立权重不适用 |
这里引用的是对应 backend 的原生 offloading 集成,不是 LMCache MP 或 KVBM 支持表。事件计数增长证明 Router 接收了消息;还需观察 tier/locality 和实际加载,才能证明路由利用了外部命中。缓存存在、可见、被选择和加载完成是四个不同事件。
3. 先解决“发现后会不会消失”
LMCache 的 prefetch_l1_lock_pass.md 给出一个明确设计合同:从 discovery 报告 hit 开始,直到读取完成,返回的 keys 必须处于有效锁定保护下。observe 与 lock 要原子化,否则 cache 命中信息在消费者使用前就可能过期。
该设计区分 L1 read locks 与 L2/reservation,L2 的 all-or-nothing reservation 失败时退回已经确认的 L1 hits;LRU 的触碰发生在被服务的 keys 上,而不是仅因加锁就刷新所有候选。这些是此版本 design 文档描述的合同,实际 backend 是否执行应由集成测试和事件验证。
对 sliding window 等模型,还要锁定当前请求真正需要的 retained state。前缀哈希相同但缺少窗口边界、压缩状态或 n-gram history,不能只靠一段 KV bytes 宣称恢复成功。
4. Lazy offload 改变了缓存何时可用
LMCache 0.5.5 文档中的 lazy offload 适用于 vLLM LMCacheMPConnector,默认关闭。开启后,完成请求的 metadata 进入 FIFO;达到阈值后,在处理至少一个 token 的 scheduling step提交一批 store。
| 配置 | 文档默认值 | 意义 |
|---|---|---|
lmcache.mp.lazy_offload | false | 延迟、批量提交 |
lmcache.mp.lazy_offload_policy | FIFO | 此版本支持的选择策略 |
lmcache.mp.lazy_offload_threshold | 100 | pending finished requests 达到多少才触发 |
lmcache.mp.lazy_offload_select_count | 10 | 每次最多取多少请求 |
被选中之前,GPU blocks 不被 pin,可能已被其他请求重用。connector 重新检查记录的 block hashes,跳过失效 store metadata,而不是缓存错误 KV。因此正确性可以保持,但未来请求会遇到更多 miss。
低于阈值的 pending requests 和流量停止后的尾批,不会自动 flush。这使“请求已经完成”与“外部 cache 已经可命中”成为两个事件。评测若先发很少请求再等 idle,不能假定所有 KV 已落入外部层。
选择 eager/lazy 应比较写入频次、主路径干扰、可复用延迟与失效比例。只报告 steady-state 吞吐而不报告缓存可用时间,会掩盖这个交换。
5. 非连续片段复用需要单独验收
CacheBlend 尝试利用 RAG 中可重复但不连续的 chunks,选择性重算与融合对应状态。固定版本文档包含 MP Blend 路径;它与严格的 prefix reuse 是不同机制。
不能把独立片段的 KV 随意拼接后声称与完整 forward 等价:位置、跨片段 attention 和 hidden-state 依赖都可能改变结果。验收应包括 task quality、logits/输出差异、重算比例和端到端延迟。未经过此类验证时,本页的容量和加载模型只用于语义兼容的 prefix/state reuse。
另一个版本边界:MP kv_cache_management.rst 中部分 move/pin/compress API 仍标为 coming soon,不能从标题推断已经提供可用运维接口。
6. 用四组对照做性能闭环
先固定 GPU 数、模型版本、ISL/OSL、到达分布、prefix 工作集和 SLO。每组都报告实际完成量、错误/重算回退、TTFT 与 ITL 分位数。
| 对照 | 控制条件 | 主要回答 |
|---|---|---|
| GPU-only cold vs warm | 工作集能放入 HBM | 本地复用基线与理论可省计算 |
| GPU-only vs external tier | 工作集超过 HBM,复用距离固定 | 外部容量是否提供额外有效命中 |
| eager vs lazy offload | 相同到达率与重复模式 | 主路径减少的工作是否抵过缓存延迟可用 |
| 本地 host vs remote backend | 相同外部有效容量、命中集合 | 拓扑、带宽、排队与竞争的影响 |
至少沿同一 request ID 收集:GPU hit tokens、external hit tokens、实际加载 bytes、lookup/lock 等待、D2H/H2D/网络区间、重算 tokens、store completion 和 GPU block 保护时长。LMCache MP 文档建议 external hit 看 vLLM 的 External prefix cache hit rate;server /status 的对象数只能证明驻留规模,不能当 token hit ratio。
最终把时长投到 Trace 关键路径:传输存在只证明做过工作,传输暴露才解释请求变慢。若收益依赖外部层,断开 backend 后还要辨认 fail、recompute 与超时行为,避免把回退重算后的正确输出误记为传输成功。
相关页面
- KV Cache:分页、CoW、驱逐与复用基础。
- KV Hit Ratio 修正模型:从命中面积走到 TTFT 与 TPM。
- P/D 分离:当前请求的交接与跨请求复用如何组合。
- Engram TP 分片与同机 DP 共享:静态大表共享的另一种容量问题。
来源与复核
- LMCache MP 文档:
disaggregated_prefill.rst、lazy_offload.rst、l2_storage/supported_storages.rst与kv_cache_management.rst。 - Prefetch L1 lock pass 设计:发现、锁定、reservation 与 LRU 合同。
- CacheBlend 文档:非连续 chunks 的选择性重算边界。
- Dynamo 1.5.1 Offloading Support Matrix:不同 backend 的 tier-aware 路由与版本门槛。
被以下页面引用(6)
修改历史1 次提交
- docs: update inference runtime and add Engram TP/DP researchweigao chen··
04637c6