跳转到主要内容

分层 KV Cache:从 GPU 命中到外部存储复用

用容量、搬运和生命周期解释 GPU—CPU—远端 KV 分层,固定 LMCache 0.5.5 的 MP、lazy offload 与锁定合同

· 约 9 分钟阅读

本文目录

Prefix Cache 的生命周期不必结束于 HBM 驱逐。分层 KV 把可复用状态保留在 CPU 内存、另一台机器或存储设备里,在下一次请求到来时决定加载还是重算。它增加的是可复用容量,同时引入搬运、发现、锁定和回收的成本。

先用 KV Cache 建立分页与复用语义,再用 KV Hit Ratio 模型 区分命中面积与端到端收益。本页的版本证据固定为 LMCache 0.5.5 05a013b29da78cf2321b9b46ec5039dde2fb0bb0;实现细节以其 MP 文档和 design 源码说明为边界,没有独立 GPU 或 RDMA 实测。

30 秒复习
  • 一句话:分层 KV 用更大的外部容量换取重算机会,但一次可发现的命中必须能在使用前完整、兼容地加载。
  • 三个判断:区分 GPU hit 与 external hit;比较关键路径上的加载时间与被省掉的计算;锁定生命周期要覆盖发现到消费完成。
  • 核心模型:外部复用的净收益约为 ΔT=Tsaved compute−Texposed load−Textra control\Delta T=T_{\text{saved compute}}-T_{\text{exposed load}}-T_{\text{extra control}},不能直接把命中率当提速比例。
  • 边界: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]
图 1 · 分层复用的逻辑路径。GPU 与外部命中分别计数;虚线表示跨请求保留,不表示每个请求都同步写完全部层级。来源:固定版本 LMCache MP 文档的 GPU → LMCache → recompute 顺序;机制示意。

这里的 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 可用

BKV=2NlayersLHKVdheadbB_{\text{KV}}=2N_{\text{layers}}L H_{\text{KV}}d_{\text{head}}b

估算,其中 bb 是每元素字节数。加载量只计被复用的 tokens,并按实际 rank 分片、block rounding、scale 与 metadata 修正;MLA、压缩 attention、SWA 和 recurrent state 需换成各自状态公式。

因此 DeepSeek V4.1 Runtime 的 packed record 大小不能直接充当所有模型的每 token 网络 payload。压缩记录、滑窗及边界恢复状态的生命周期不同,connector 是否完整支持需要单独证明。

2.2 用有效带宽判断加载下限

Tload≳Tlookup/lock+BreuseBWeffective+Tlayout/restoreT_{\text{load}}\gtrsim T_{\text{lookup/lock}}+ \frac{B_{\text{reuse}}}{BW_{\text{effective}}}+ T_{\text{layout/restore}}

这是单条串行路径的下限模型。多跳的 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 OffloadingConnectorvLLM ≥ 0.24.0、Dynamo ≥ 1.3.0;aggregated CPU RAM 可按 tier 路由Disk 的 STORAGE 映射尚未完全验证;remote/shared-pool 事件索引仍在建设
SGLang HiCacheSGLang ≥ 0.5.11、Dynamo ≥ 1.2,GPU/host events 可区分Mooncake shared pool 路径要求 SGLang ≥ 0.5.13,并显式配置 shared cache
TensorRT-LLM native host cacheDynamo ≥ 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_offloadfalse延迟、批量提交
lmcache.mp.lazy_offload_policyFIFO此版本支持的选择策略
lmcache.mp.lazy_offload_threshold100pending finished requests 达到多少才触发
lmcache.mp.lazy_offload_select_count10每次最多取多少请求

被选中之前,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 与超时行为,避免把回退重算后的正确输出误记为传输成功。

相关页面

来源与复核

修改历史1 次提交