LLM Infer Infra 学习资料库

LMCache 专项:系统设计题与源码阅读

白话导读:三道共享 KV 层系统设计题的完整推演,加上按问题找源码的导航。

  • 设计题一给出完整模板:需求、容量、带宽、组件流程、降级和验收。
  • 设计题二、三分别考 PD 分离与复用的组合、RAG 片段顺序变化对复用的影响。
  • 源码导航按“要回答的问题”组织,而不是按目录。

先独立做一遍设计题一,再对照参考推演。

1. 设计题一:长文档问答的共享 KV 层

1.1 需求与假设

题目:一个 RAG 服务用的是普通 GQA 模型(32 层、8 个 KV head、head 维度 128、BF16)。每次输入 8K token,其中常见的文档前缀约 6K;峰值 20 请求/秒;热门文档前缀约 1,000 个。目标是降低 TTFT,同时不明显拖慢 Decode 的尾延迟。这些数字是练习用的,不是 LMCache 或 Mooncake 的公开测试结果。

先向面试官问清楚:

如果 system prompt 各不相同,普通前缀缓存能共享的部分会大幅减少,后面的预算都要重算。

1.2 容量预算

每 token 128 KiB:

一个对象可以有多个副本,对象数和副本数不要混。如果有多个组或换了 chunk 策略,对象数还会变。在这个均匀切分的例子里,每个 rank 的每个 chunk 是 8 MiB。可以用容量规划工具验证。

1.3 带宽与写入预算

如果 20 个请求每秒全部从远端读完整的 6K 前缀:

B read = 20 × 0.75 = 15 GiB/s ≈ 128.85 Gbit/s

这只是数据本身的总读取量,不含协议开销、本机 H2D、控制面和流量波动。一张 200G 网卡的线速是 25 GB/s,约 23.28 GiB/s;按 70% 有效利用率算,约 16.30 GiB/s,已经非常接近 15 GiB/s 的持续读负载。这点余量撑不住突发、故障和复制。

写入:如果 10% 的请求产生新的完整 8K 前缀(每条 1 GiB),两副本的写流量是 20 × 10% × 1 × 2 = 4 GiB/s。读和写是不是挤同一个方向、同一张网卡、同一条 PCIe、同一个存储池,要按实际拓扑拆开看;不能把全双工两个方向简单相加就说超了线速,但内存带宽、CPU 和交换网络仍可能是共同瓶颈。

元数据:每秒约要查 20 × 24 × 4 = 1,920 个对象。批处理能减少 RPC 次数,但目录的工作量还在;还要算上保存、续租、淘汰和重试的流量。

在途内存:如果每份数据平均在 staging 停留 100 ms,15 GiB/s 意味着平均约 1.5 GiB 在途;还要给 P99 和突发留余量。

1.4 组件与请求流程

查看图源
flowchart TB
  API["Gateway / 鉴权 / 限流"] --> ROUTE["缓存感知 Router"]
  ROUTE --> ENGINE["兼容的 vLLM 实例池"]
  ENGINE <--> LOCAL["每节点 LMCache MP / host L1"]
  LOCAL <--> POOL["Mooncake Store / 远端内存池"]
  POOL -.-> MASTER["Master / HA 控制面"]
  INDEX["可选缓存目录 / 事件索引"] -.-> ROUTE
  LOCAL -.-> INDEX
  OBS["Metrics / Traces / SLO"] -.-> ENGINE
  OBS -.-> LOCAL
  OBS -.-> POOL
  1. 网关做认证,确定这个请求能用哪个租户/模型的命名空间。
  2. 路由同时看队列长度、前缀在哪、加载要多少代价,选出候选实例。
  3. 引擎先看本地 APC 命中多少;LMCache 再查还能额外复用多少。
  4. 在保护和内存预算的约束下,从 L1/L2 加载,并检查所有需要的 rank 和组是否齐全。
  5. 把命中的部分放进 GPU,计算剩下的 Prefill 和 Decode。
  6. 值得复用的数据异步保存;事件索引用来辅助路由,但真正读取时仍要验证对象状态。

1.5 降级与一致性

1.6 验收标准

用同一份请求 trace,比较“只有 APC”“APC + L1”“APC + 远端缓存”三种配置的:TTFT/ITL 的 P50/P95/P99、goodput、GPU 利用率和抢占、实际传输量、命中 token、主机内存与 staging 占用、失败率和输出正确性。再测一次节点退出时的尾延迟和恢复时间——如果平均收益很高,但一出故障就把 GPU 压垮,方案还没到生产标准。

2. 设计题二:PD 分离 + 跨请求复用

先别急着选传输库,先分清两种数据需求:

学习版本的 LMCache MP 做法是在 MultiConnector 里同时用 NixlConnector 和 LMCacheMPConnector,两边的引擎各配一个 LMCache server。版本前提和 real-blocks 修复要求见 PD 分离指南。别的系统也可以用 Mooncake Transfer Engine 做交接,但不能照搬 NIXL 的配置。

容量要分开算:请求级交接的速率、跨请求读写的速率、Decode 端在途序列的 KV、TP/PP 布局是否兼容、交接期间的双份 buffer、副本保存多久。Prefill 和 Decode 的并行度不同时,必须有验证过的布局转换(重新切分)支持——“字节传成功了”不代表布局会自动转换。

面试官会追问:首 token 由哪个阶段产生?路由怎样转发流式输出?Prefill 什么时候可以释放原来的 GPU KV?Decode 超时后,谁来清理哪些对象?跨请求缓存写失败会不会影响当前请求?这些答案要来自具体协议,而不是画几个方框。

3. 设计题三:RAG 片段顺序变化

同一个文档,放在不同的 system prompt 后面,或者排在其他文档的前后,普通前缀命中都会减少。有三类做法:

  1. 统一模板和文档顺序,提高真正相同的前缀比例;代价是可能要改业务的提示词设计。
  2. 只缓存稳定的共同前缀,其余部分重算;简单,也好验证。
  3. 用 CacheBlend 这类非前缀复用加选择性重算;需要在模型和任务上验证质量,还需要额外的运行时支持。

比较方案时要同时报告质量和时延,不能只统计“文档块在存储里有没有”。也不能把旧的 K 做一下位置旋转,就说所有层都和新上下文一致了。

4. 源码导航:按问题找文件

下面都是 LMCache 仓库里的相对路径。读法是先看设计文档,再看实现,最后看测试。这些只是入口,不要求一个月内把整个目录精读完。

想弄清楚 设计文档 实现与测试
vLLM 查命中怎么推进? docs/design/integration/vllm/mp_lookup_state.md lmcache/integration/vllm/mp_lookup_state.py; tests/v1/test_mp_lookup_state.py
key 与多 group 如何表示? docs/design/v1/distributed/storage_manager.md lmcache/v1/distributed/api.py; lmcache/v1/multiprocess/token_hasher.py
谁保护正在写的数据? docs/design/v1/distributed/l1_manager.md lmcache/v1/distributed/l1_manager.py; tests/v1/distributed/test_l1_manager.py
跨层预取如何规划与限流? docs/design/v1/distributed/storage_controllers/prefetch_controller.md lmcache/v1/distributed/storage_controllers/prefetch_controller.py
L2 adapter 要遵守什么? docs/design/v1/distributed/l2_adapters/overall.md lmcache/v1/distributed/l2_adapters/base.py
如何接 Mooncake? Mooncake adapter 指南 lmcache/v1/distributed/l2_adapters/mooncake_store_l2_adapter.py; csrc/storage_backends/mooncake/
GPU KV layout 从哪里识别? docs/design/v1/gpu_connector/layout-invariant.md lmcache/v1/gpu_connector/utils.py; lmcache/v1/gpu_connector/kv_format/
copy 为什么有不同路径? docs/design/v1/multiprocess/lmcache_driven_transfer_copy_paths.md lmcache/v1/multiprocess/object_group_transfer.py
抢占恢复如何验证? docs/design/integration/vllm/mp_preemption_correctness.md lmcache/integration/vllm/vllm_multi_process_adapter.py
SGLang 集成哪里不同? docs/design/integration/sglang/lmcache-unified-radix-cache.md lmcache/integration/sglang/
旧版 LMCacheEngine 在哪里? 进程内模式资料 lmcache/inprocess/v1/cache_engine.py; lmcache/inprocess/v1/token_database.py

LMCache 上游的测试可能依赖 GPU、native 扩展和测试夹具;做了离线练习不等于跑过这些测试。测试环境和命令以上游的 AGENTS.md 和贡献指南为准。

Mooncake 对照入口(Mooncake 仓库相对路径):

5. 进一步阅读

5.1 先跑起来

5.2 带着问题读论文

论文里的实验结果只适用于它报告的配置,替代不了自己复现;也不要把论文里的设计都说成现在的默认实现。每篇带一个问题去读:

5.3 选一个方向深挖

一个月比较现实的目标是:吃透一条完整链路,再深挖一个点,而不是背完所有框架的所有参数。面试时用自己真正做过的实验和证据回答,分清哪些是实测、哪些是读来的结论、哪些是设计假设。

输入主题、术语或问题