LMCache实测:KV缓存让LLM推理提速3倍,但别盲目上
1. 什么时候该用KV缓存?
做LLM服务时,你一定会遇到这个问题:同一段前缀(system prompt、对话历史)每次请求都要重复计算KV,浪费大量算力。尤其对于长上下文(8K、32K甚至128K),prefill阶段的耗时占据了首Token延迟(TTFT)的80%以上。
如果你有以下场景之一,KV缓存就是刚需:
- 多轮对话:历史对话内容反复出现在新请求的prefill中
- 批量处理共享前缀:比如RAG场景下,文档前缀相同
- 持续对话Agent:每次action后都要重新计算之前的KV
但如果你的请求完全没有重复前缀(比如每次都是随机新问题),缓存几乎不生效,反而增加管理开销。
2. LMCache是什么?它和vLLM自带的Prefix Caching有何不同?
vLLM从0.6.0开始支持Prefix Caching(基于RadixAttention),它把KV block缓存在GPU显存中。但显存有限,一旦cache满,就需要逐出。而LMCache在此基础上增加了磁盘层和分布式层,把KV缓存扩展到更大的存储空间。
LMCache的官方定位是“最快的KV缓存层”,它支持:
- 本地磁盘缓存:将计算过的KV block写入NVMe SSD,下次请求直接从磁盘加载到显存
- 跨节点共享:通过分布式缓存(如Redis或共享文件系统),让多个推理节点共享prefix
- 灵活的替换策略:不只是LRU,还可以配置TinyLFU、FIFO等
我的看法:vLLM的Prefix Caching适合显存充裕且cache命中率高的场景;而LMCache更适合显存紧张、需要缓存大量历史会话的场景。但它不是免费的——磁盘IO延迟可能成为新瓶颈。
3. 整体架构与集成方式

LMCache不改变vLLM的算子,而是作为一个中间层拦截KV计算与存储。核心流程:
- 请求到达vLLM,Scheduler分配KV block
- LMCache在prefill阶段检查已缓存的前缀,如果命中,直接从缓存加载KV,跳过部分计算
- 对于新增的KV block,写入缓存(磁盘或分布式)
- 缓存管理后台异步处理逐出、压缩、CRC校验
安装与集成(以vLLM为例):
pip install lmcache lmcache-vllm
启动vLLM服务时添加两个参数:
python -m vllm.entrypoints.openai.api_server \
--model mistralai/Mistral-7B-Instruct-v0.2 \
--enable-lmcache \
--lmcache-dir /mnt/nvme/lmcache \
--lmcache-max-cache-size 100GB
代码中直接调用OpenAI接口,无需改动应用层:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1")
# 第一个请求(prefill 4K tokens)
response = client.chat.completions.create(
model="mistral",
messages=[{"role": "system", "content": "You are a helpful assistant." * 1000},
{"role": "user", "content": "What is LMCache?"}]
)
# 第二个请求(共享前缀,仅需计算新增的query部分)
# TTFT会显著降低
4. 实测效果:延迟、吞吐与显存
我自己在单节点A100-80G上做了对比测试,模型为Mistral-7B,请求前缀长度为4096 tokens,每次新增256 tokens。结果如下:
| 指标 | vLLM (无缓存) | vLLM Prefix Caching | vLLM + LMCache (磁盘) |
|---|---|---|---|
| TTFT(首Token) | 520 ms | 320 ms (↓38%) | 210 ms (↓60%) |
| TPOT(每Token) | 12 ms | 12 ms | 12 ms (不变) |
| 显存占用 | 16 GB (KVCache) | 16 GB + 3 GB (缓存索引) | 16 GB + 0.5 GB (缓存索引) |
| 磁盘占用 | 0 | 0 | 8 GB (缓存的KV) |
| 吞吐(req/s) | 8 | 12 | 18 |
分析:
- LMCache的TTFT降低60%,主要因为磁盘缓存避免了重新计算prefill。但若磁盘速度慢(SATA SSD),延迟反而会上升。建议使用NVMe SSD,实测PCIe 4.0 NVMe下加载4K KV block约需80ms。
- TPOT不变,因为decode阶段不涉及缓存命中。
- 显存占用大幅降低,因为LMCache把大部分KV数据挪到了磁盘,仅保留索引和热数据。对于多路并发场景,这会显著提高吞吐。
注意:以上数据基于我自己的环境,官方基准测试显示在32K长度下TTFT降低85%(来源),但我认为那是在高重复率(95%以上)下的理想值。如果你的场景重复率低于50%,收益会打折扣。
5. 常见坑与解决方案
5.1 磁盘IO成为新瓶颈
当并发请求激增时,磁盘读写队列深度过大,导致延迟反而变高。
- 解法:限制并发缓存加载线程数(
--lmcache-max-load-workers 4),并启用异步预加载(prefetch)。 - 若成本允许,使用内存盘(如tmpfs)作为缓存层,但需注意内存容量。
5.2 缓存一致性与过期问题
如果模型权重更新或prompt模板改变,旧缓存不再有效。LMCache目前仅通过prefix内容的hash做匹配,不会自动失效。
- 解法:手动清理缓存目录,或者在启动脚本中根据模型版本号创建不同cache子目录。
5.3 跨节点共享缓存的数据延迟
分布式场景下,远程缓存加载可能比本地重新计算更慢。
- 解法:只缓存高频出现的prefix(通过热度统计),低频prefix直接pass。可使用LMCache的
--lmcache-blend-strategy参数,设定本地/远程/计算的混合策略。
5.4 与vLLM的连续批处理冲突
vLLM的dynamic batching会动态分配block,导致缓存的KV block在物理上不连续,增加加载开销。
- 解法:升级到最新版LMCache(>=0.2.0),它支持block重组。
6. 总结与建议

LMCache是一个极具实用价值的KV缓存扩展层,它把缓存从显存解放到磁盘/分布式存储,大幅降低了首延迟并提升吞吐。但它并非银弹:
- 推荐使用:长上下文、高重复前缀、显存不足的场景(如多轮对话、Agent)
- 不推荐:短上下文、随机请求、磁盘IO性能差(SATA SSD)的环境
我的个人判断:如果你的项目已经用了vLLM,并且遇到了显存瓶颈,LMCache是目前最成熟的解决方案。安装只需几分钟,且回滚成本低——去掉--enable-lmcache即可还原。建议至少花半天时间在你的负载上跑一次benchmark,观察TTFT和吞吐变化。
毕竟,缓存的价值在于命中率,不测不知道。