HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于

vLLM 原理:PagedAttention 和 Continuous Batching

vLLM 是目前最流行的大模型推理框架,速度快、吞吐高。

核心技术两个:PagedAttention 和 Continuous Batching。这篇讲清楚它们的原理。


vLLM 是什么

vLLM 是加州大学伯克利分校开源的大模型推理引擎。

主打:高吞吐、低显存浪费。

GitHub:https://github.com/vllm-project/vllm

为什么快

传统推理框架的问题:

  1. KV Cache 预分配,显存浪费严重
  2. 静态 Batching,GPU 利用率低

vLLM 解决了这两个问题。


PagedAttention

传统 KV Cache 的问题

传统做法:为每个请求预分配固定大小的 KV Cache。

请求1:预分配 4096 tokens 的空间
实际只用了 500 tokens
浪费率:88%

更糟的是,不同请求的 KV Cache 是连续分配的:

显存布局:
[请求1: 4096][请求2: 4096][请求3: 4096]...

如果请求2结束了:
[请求1: 4096][空洞: 4096][请求3: 4096]...

产生碎片,新请求可能因为找不到连续空间而无法分配。

PagedAttention 的思路

借鉴操作系统的虚拟内存:把 KV Cache 分成固定大小的「页」(block)。

每页存 16 个 token 的 KV

请求1 需要 500 tokens → 分配 32 页
请求2 需要 1000 tokens → 分配 63 页

页可以不连续

工作原理

1. 页表管理

每个请求有一个页表,记录它的 KV Cache 在哪些页上:

请求1 的页表:[页3, 页7, 页12, 页15, ...]
请求2 的页表:[页1, 页5, 页8, 页20, ...]

2. 按需分配

生成 token 时,页不够就分配新页:

请求1 当前 500 tokens,用了 32 页
生成第 501 个 token,还在第 32 页里
生成第 513 个 token(新页),分配第 33 页

3. 及时释放

请求结束,页立即归还:

请求2 结束 → 释放 [页1, 页5, 页8, 页20, ...]
这些页可以给新请求用

优势

1. 几乎零浪费

只分配实际需要的页,不预留最大长度。

传统:每个请求分配 4096 tokens 空间
PagedAttention:用多少分多少

实测显存利用率从 ~50% 提升到 ~95%

2. 无碎片

页是固定大小,用完就还,不产生碎片。

3. 支持共享

相同前缀的请求可以共享 KV Cache:

请求1:「你好,请介绍一下北京」
请求2:「你好,请介绍一下上海」

「你好,请介绍一下」的 KV Cache 可以共享

Beam Search、Parallel Sampling 等场景效率大增。


Continuous Batching

传统 Batching 的问题

静态 Batching:凑够一批请求一起处理。

等待凑够 batch_size=8 的请求
开始处理
所有请求都完成后,处理下一批

问题:

  1. 等待时间长(要凑够一批)
  2. 短请求等长请求(一批里最长的请求完成才能开始下一批)
请求1:生成 10 个 token,很快完成
请求2:生成 500 个 token
请求3:生成 20 个 token

静态 Batching:
请求1 等请求2,要等很久
请求3 也等请求2
GPU 在处理请求2 时,请求1 和 3 的位置空着

Continuous Batching

动态调度:请求随到随处理,完成随时离开。

Iteration 1:处理 [请求1, 请求2, 请求3]
请求1 完成,离开

Iteration 2:处理 [请求2, 请求3, 请求4(新来的)]
请求3 完成,离开

Iteration 3:处理 [请求2, 请求4, 请求5(新来的)]
...

每次迭代:

  1. 检查有没有请求完成,释放位置
  2. 检查有没有新请求,加入 batch
  3. 执行一步推理

优势

1. 延迟更低

新请求不用等凑批,来了就能处理。

2. 吞吐更高

GPU 始终在满负荷工作,不浪费位置。

静态 Batching:完成率波动大
Continuous Batching:稳定的高吞吐

3. 短请求不等长请求

10 token 的请求生成完就离开,不用等 500 token 的请求。


vLLM 的调度

PagedAttention 解决显存问题,Continuous Batching 解决调度问题。vLLM 把两者结合起来。

调度流程

while True:
    # 1. 检查完成的请求
    for req in running_requests:
        if req.finished():
            release_pages(req)
            running_requests.remove(req)

    # 2. 检查新请求
    while has_free_pages() and waiting_requests:
        req = waiting_requests.pop()
        allocate_pages(req)
        running_requests.add(req)

    # 3. 执行一步推理
    outputs = model.forward(running_requests)

    # 4. 更新 KV Cache
    for req, output in zip(running_requests, outputs):
        req.append_token(output)

Preemption(抢占)

显存不够时,可以把一些请求「挂起」:

显存快满了
请求3 优先级低,暂时挂起
释放请求3 的页
给更紧急的请求用
请求3 稍后恢复(重新计算或从 swap 恢复)

vLLM 支持两种抢占模式:

  • Recompute:重新计算 KV Cache
  • Swap:把 KV Cache 换到 CPU

使用 vLLM

安装

pip install vllm

离线推理

from vllm import LLM, SamplingParams

llm = LLM(model="meta-llama/Llama-2-7b-hf")

prompts = [
    "Hello, my name is",
    "The capital of France is",
    "The future of AI is",
]

sampling_params = SamplingParams(
    temperature=0.8,
    top_p=0.95,
    max_tokens=256
)

outputs = llm.generate(prompts, sampling_params)

for output in outputs:
    print(output.outputs[0].text)

在线服务

# 启动服务
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-2-7b-hf \
    --host 0.0.0.0 \
    --port 8000

# 调用(兼容 OpenAI API)
curl http://localhost:8000/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "meta-llama/Llama-2-7b-hf",
        "prompt": "Hello, my name is",
        "max_tokens": 100
    }'

重要参数

LLM(
    model="...",

    # 显存相关
    gpu_memory_utilization=0.9,  # GPU 显存利用率
    max_model_len=4096,          # 最大上下文长度

    # 并行相关
    tensor_parallel_size=2,      # 张量并行(多卡)

    # 量化
    quantization="awq",          # 量化方法

    # KV Cache
    block_size=16,               # 页大小(tokens)
)

性能对比

vs HuggingFace Transformers

指标HF TransformersvLLM
吞吐(tokens/s)基准2-4x
显存利用率~50%~95%
延迟较高较低

实测数据

LLaMA-7B,单卡 A100:

并发数HF (tokens/s)vLLM (tokens/s)
13035
8100250
32150800
128OOM1500

并发越高,vLLM 优势越明显。


局限性

1. 首 token 延迟

PagedAttention 有一些额外开销,TTFT 可能略高于简单实现。

对延迟极其敏感的场景要注意。

2. 显存开销

页表管理本身需要一些显存。

小模型或单请求场景,优势不明显。

3. 模型支持

不是所有模型都支持,需要适配。

主流模型(LLaMA、Mistral、Qwen 等)都支持了。


其他优化

vLLM 还有一些其他优化:

FlashAttention

优化 Attention 计算的访存模式,减少显存访问。

vLLM 集成了 FlashAttention。

Speculative Decoding

用小模型快速生成草稿,大模型验证。

一次验证多个 token,减少大模型调用次数。

Prefix Caching

缓存常用 prefix 的 KV Cache,避免重复计算。

比如系统 prompt 被很多请求共用,可以缓存起来。


小结

vLLM 的核心技术:

PagedAttention:

  • 把 KV Cache 分页管理
  • 按需分配,无碎片
  • 支持共享
  • 显存利用率从 50% 提升到 95%

Continuous Batching:

  • 动态调度请求
  • 请求随到随处理,完成随走
  • 短请求不等长请求
  • GPU 利用率大幅提升

效果:

  • 吞吐提升 2-4 倍
  • 支持更高并发
  • 延迟更稳定

推理服务首选 vLLM。

下一篇对比主流推理框架:vLLM vs TensorRT-LLM vs SGLang。