在大语言模型推理服务中,GPU 显存是稀缺资源。vLLM 通过 PagedAttention 实现了 KV Cache 的分块管理,使得显存可以像操作系统内存一样被灵活分配与回收。然而,当显存压力增大时,系统必须决定哪些块应该被驱逐腾出空间。这一决策由块驱逐策略完成,vLLM 目前支持 LRU(最近最少使用)与 LFU(最不经常使用)两种算法。本文将从算法原理、适用场景与工程配置三个维度,为开发者提供具体的策略选型依据。
PagedAttention 的块管理机制
在深入驱逐策略之前,有必要理解 vLLM 的块级内存管理架构。PagedAttention 将 KV Cache 划分为固定大小的块(block),每个块默认包含 16 个 token 的键值对。这种设计借鉴了操作系统的虚拟内存分页机制:每个序列的 KV Cache 不需要连续存储,块可以分散在 GPU 显存的不同位置,通过页表映射实现逻辑上的连续访问。
BlockManager 负责块的分配与释放。当新的序列进入推理阶段时,BlockManager 从空闲块池中分配足够的块来存储其 KV Cache;当显存接近阈值时,需要为新序列腾出空间,此时触发块驱逐。驱逐策略的选择直接影响缓存命中率与推理吞吐量。
LRU 策略:时间局部性的守护者
LRU(Least Recently Used)策略的核心思想是保留最近被访问过的块,驱逐最长时间未被访问的块。这一算法假设数据的访问存在时间局部性 —— 最近被使用的内容在未来更可能被再次访问。
在 vLLM 的实现中,LRU 策略维护一个块的时间戳或访问队列。每当某个块被读取或写入时,该块会被移动到队列的尾部;当需要驱逐时,系统选择队列头部的块进行回收。对于大语言模型推理场景,LRU 策略天然适合处理突发性的请求流:当用户频繁提交新的推理请求时,最近完成的请求所使用的块会被保留,以便快速响应可能的续写需求。
然而 LRU 策略存在明显的局限性。在 prefix caching 场景下,相同的系统提示词(system prompt)会被大量请求重复使用。如果这些块因为时间较早被 LRU 驱逐,后续请求将不得不重新计算 prefix 的 KV Cache,导致算力浪费。换言之,LRU 对访问频率不敏感,无法有效利用重复访问的空间局部性。
LFU 策略:频率局部性的优化者
LFU(Least Frequently Used)策略转而关注访问频率而非访问时间。系统为每个块维护一个访问计数器,当块被访问时计数器递增;当需要驱逐时,选择计数器值最低的块进行回收。这一策略假设高频访问的内容值得保留,低频访问的内容可以被替换。
对于面向大量相似请求的在线推理服务,LFU 策略能够更有效地保留热门内容的缓存。例如,当系统使用相同的 system prompt 处理数千次请求时,承载该 prompt KV Cache 的块将保持很高的访问频率,即使这些请求在时间上分散,LFU 策略也不会将其驱逐。实验数据表明,在 prompt 复用率较高的场景下,LFU 策略可以将 KV Cache 命中率提升 15% 至 30%。
LFU 策略的主要风险在于冷启动问题。新分配的块初始计数为 0,在统计周期内可能被误驱逐;此外,热点内容变化时,旧的热点块可能占用显存直到其计数器被新的热点超越。
场景化策略选择与参数配置
基于上述分析,我们可以提炼出策略选择的决策树。当推理服务以长会话、复杂上下文为主时,LRU 策略更能适应动态变化的访问模式;当服务处理大量相似 prompt 或存在明确的 prefix caching 需求时,LFU 策略更能发挥频率局部性的优势。
在 vLLM 的实际部署中,驱逐策略通过启动参数指定:--block-eviction-policy lrul 或 --block-eviction-policy lfu。以下是面向不同场景的推荐配置:
| 场景 | 推荐策略 | 关键参数 | 预期收益 |
|---|---|---|---|
| 突发请求流、请求多样性高 | LRU | gpu_memory_utilization=0.9 | 快速响应新请求,减少 preemption |
| 固定 system prompt、大量相似请求 | LFU | gpu_memory_utilization=0.85, enforce_eager=False | 提升 prefix 命中率,降低延迟 |
| 混合场景、无明确偏好 | LRU 起步 | 观察 kv_cache_hit_rate 调整 | 渐进式优化 |
工程落地要点
实际部署中,除了选择算法,还需要关注以下监控指标与调优点:
显存利用率监控:gpu_memory_utilization 参数设定了 vLLM 使用的显存上限,建议从 0.9 开始,根据 oom 错误频率逐步下调。低于 0.8 时可能表明存在显存碎片或块分配效率问题。
驱逐频率追踪:通过日志或 Prometheus 指标观察 num_block_swaps,该指标反映了每秒发生的块驱逐次数。如果驱逐频率过高,可能需要增大 num_gpu_blocks 或调整策略。
缓存命中率分析:KV Cache 命中率是驱逐策略有效性的直接指标。使用 vLLM 的内建指标 kv_cache_blocks_hit_ratio 进行观测,LFU 策略下该指标通常应高于 0.6。
动态调整能力:vLLM 当前版本不支持运行时动态切换驱逐策略。如需实验不同策略,建议使用生产流量的影子模式(shadow mode)进行 A/B 测试,确认效果后再全量切换。
综合来看,LRU 与 LFU 策略代表了两种不同的缓存哲学:前者拥抱变化,适合动态负载;后者坚守热点,适合稳定访问模式。工程团队应基于实际请求特征进行选择,并通过持续监控迭代优化。
参考资料:vLLM 官方文档(https://docs.vllm.ai/)