3、vLLM核心概念:PagedAttention原理、Continuous Batching、KV Cache管理、vLLM的架构与组件

聊到vLLM,绕不开的就是那几个核心概念。说实话,我第一次接触PagedAttention时,脑子里想的是「这不就是操作系统的虚拟内存吗?」后来仔细一看,还真是异曲同工。这一章,我就把vLLM的几根顶梁柱拆开来讲,包括PagedAttention、Continuous Batching、KV Cache管理,还有整体架构。

3.1 为什么需要PagedAttention?

先说说背景。大模型推理时,Transformer的每一层都会产生KV Cache。这个Cache有多大呢?我举个例子:一个70B的模型,如果输入序列长度是2048,batch size是16,那KV Cache可能要吃掉几十GB的显存。

问题在于,传统的实现方式是把KV Cache当作一个连续的大块内存来分配。你想想看,每个请求的长度不一样,有的长有的短,但系统得按最大可能长度去预留空间。这就造成了严重的碎片化和浪费。

核心痛点:显存利用率低,大量空间被闲置。我曾经在一个项目中,发现KV Cache的利用率只有40%左右,剩下的全浪费了。

3.2 PagedAttention原理

PagedAttention的灵感来自操作系统的分页内存管理。它把KV Cache切分成固定大小的「块」(Block),每个块可以独立分配和释放。请求的KV Cache不再需要连续存储,而是通过一个「块表」(Block Table)来映射。

具体来说,PagedAttention做了这几件事:

  • 分块存储:每个Block通常包含固定数量的token(比如16个或32个)的KV值。
  • 逻辑到物理的映射:每个请求维护一个逻辑块表,指向物理显存中的实际块。
  • 按需分配:只有真正用到的块才分配物理显存,避免了预分配浪费。
  • 共享机制:多个请求可以共享相同的物理块(比如在Beam Search或Prefix Caching场景下)。

我的经验:在实际压测中,PagedAttention能把显存利用率从40%提升到90%以上。尤其是长序列场景,效果非常明显。

下面这张图展示了PagedAttention的核心逻辑:

PagedAttention 核心逻辑 逻辑块表 Block 0 → 物理块 3 Block 1 → 物理块 7 Block 2 → 物理块 1 Block 3 → 物理块 5 物理显存(Block Pool) 块 0 块 1 块 2 块 3 块 4 块 5 块 6 块 7 共享机制 请求A的Block 2 和 请求B的Block 0 → 指向同一个物理块(块1) 按需分配 只有实际用到的块才分配物理显存,避免预分配浪费

3.3 Continuous Batching(连续批处理)

传统的批处理方式是「静态批处理」:等一批请求凑齐了,一起推理,一起返回。这有个问题——如果某个请求的生成长度特别长,其他短请求就得干等着。

Continuous Batching的思路是:在推理过程中动态调整批次。每生成一个token,就把已经完成的请求踢出去,把新来的请求加进来。说白了,就是让GPU一刻都不闲着。

关键点:Continuous Batching要求推理引擎支持「序列级」的调度,而不是「请求级」的调度。vLLM通过PagedAttention的块级管理,天然支持这种细粒度的调度。

我举个例子:假设当前批次有4个请求,其中2个已经生成了结束符。传统做法是等剩下2个也完成,再一起返回。但Continuous Batching会立即把完成的2个踢出,换入2个新请求。GPU的利用率从60%直接拉到95%以上。

避坑指南:我曾经在压测时发现,如果请求的生成长度差异太大(比如有的生成10个token,有的生成1000个),Continuous Batching的效果会打折扣。建议在业务层做一下长度分组,效果更好。

3.4 KV Cache管理

KV Cache的管理是vLLM性能的关键。说白了,就是怎么高效地存、怎么快速地取。

vLLM的KV Cache管理有几个要点:

  • 预分配策略:启动时预先分配一大块显存作为Block Pool,避免运行时频繁分配。
  • 内存复用:请求结束后,它的物理块会被回收,放入空闲列表,供后续请求使用。
  • Copy-on-Write:当多个请求共享同一个物理块时,如果某个请求需要修改该块,会先复制一份再修改,避免影响其他请求。
  • Swap机制:当显存不足时,可以把不常用的块换到CPU内存。虽然慢,但总比OOM强。
管理策略 作用 我的评价
预分配Block Pool 减少运行时分配开销 必须做,不然启动后性能会抖动
内存复用 提高显存利用率 PagedAttention的天然优势
Copy-on-Write 保证共享安全 Beam Search场景下特别有用
Swap to CPU 避免OOM 能不用就不用,CPU->GPU传输很慢

注意:Swap机制虽然能救急,但会显著增加延迟。我在压测时遇到过因为频繁Swap导致TP99飙升的情况。建议通过调整max_num_seqs和max_model_len来避免触发Swap。

3.5 vLLM的架构与组件

vLLM的整体架构,我习惯把它分成三层:

  1. 调度层(Scheduler):负责管理请求队列、决定哪些请求进入当前批次、分配和回收KV Cache块。
  2. 执行层(Executor):负责实际的模型推理,包括Attention计算、FFN计算等。vLLM支持多种后端,比如CUDA、ROCm、TPU。
  3. 服务层(API Server):提供HTTP/gRPC接口,接收请求、返回结果。支持流式输出和批处理。

下面这张图展示了vLLM的组件关系:

vLLM 架构与组件 服务层(API Server) HTTP/gRPC接口 · 流式输出 · 请求排队 调度层(Scheduler) 请求队列管理 · 批次调度 · Block分配/回收 Continuous Batching · 优先级调度 执行层(Executor) 模型推理 · Attention计算 · FFN计算 Block Manager 物理块分配 块表维护 共享管理 Cache Engine KV Cache管理 内存复用 Swap调度

vLLM的组件之间通过事件驱动的方式协作。调度层收到新请求后,会向Block Manager申请物理块,然后通知执行层开始推理。推理过程中,Cache Engine负责管理KV Cache的读写和复用。

我的习惯:在部署vLLM时,我会重点关注调度层的配置,比如max_num_seqs、max_model_len、gpu_memory_utilization。这几个参数直接影响吞吐量和显存利用率。调好了,性能能翻倍。

嗯,这一章的内容就到这里。PagedAttention、Continuous Batching、KV Cache管理,这三者环环相扣,共同构成了vLLM高性能推理的基石。理解了这些,后面讲压测配置和调优时,你就能明白每个参数背后的逻辑了。

一句话总结:PagedAttention解决了显存碎片化问题,Continuous Batching榨干了GPU利用率,KV Cache管理保证了内存的高效周转。三者缺一不可。

专注资料整理