08高性能生产部署——vLLM 部署本地大模型(PagedAttention 原理 + 实操)
第8篇:高性能生产部署——vLLM 部署本地大模型(PagedAttention 原理 + 实操)
本文为「本地大模型部署系列」第8篇,完整系列持续更新中。
前言
本篇是整个系列技术含量最高的一篇,也是最贴近真实生产场景的一篇。读完你不仅能跑起 vLLM,还能在面试中清晰讲出 PagedAttention——这是很多工程师的知识盲区。
在前几篇里,我们用 Ollama 实现了「一键拉起模型」,用 llama.cpp 实现了「低配机器也能跑」,用 FastChat 实现了「多模型统一 API 入口」。但如果你面对的是这样的场景:
- 生产环境同时有 50+ 并发用户 请求模型
- 公司要求接口 P95 延迟 < 2 秒
- 服务器是 A100/H100,不能让昂贵的 GPU 闲着
- 需要对外提供 OpenAI 兼容的企业级 API 服务
那前面的工具都不够用了——你需要 vLLM。
vLLM 是目前工业界公认的 高吞吐 LLM 推理引擎首选,由 UC Berkeley Sky Lab 开源。它解决的核心问题是:如何让一块 GPU 同时服务尽可能多的请求,同时保持低延迟。
本篇学完你将掌握:
- PagedAttention 核心原理(能在面试中清晰讲出来)
- vLLM 完整部署流程(pip 安装 → 启动服务 → API 调用)
- 流式输出、量化模型加载、多 GPU 并行的完整实现
- 高并发压测脚本,直观感受吞吐量提升
- 与 Ollama / llama.cpp / FastChat 的性能对比数据
- 踩坑解决方案 + 生产场景下的工程选型逻辑
一、核心原理极简讲解
要用好 vLLM,首先得搞清楚它为什么快——这不是纸面功夫,而是调参、排错、面试的底气来源。这一节不讲数学公式,只讲工程视角下你必须懂的核心逻辑。
1.1 vLLM 的定位
先建立整体认知,再深入核心机制。
vLLM(very Large Language Model serving)是一个专为高吞吐 LLM 推理设计的引擎,核心特性:
| 特性 | 说明 |
|---|---|
| PagedAttention | 革命性 KV Cache 管理,大幅减少显存浪费 |
| Continuous Batching | 动态批处理,GPU 利用率趋近 100% |
| OpenAI 兼容 API | 开箱即用,一行代码切换 |
| 量化支持 | FP16 / BF16 / AWQ / GPTQ / SqueezeLLM |
| 多卡并行 | Tensor Parallelism 原生支持 |
一句话定位:Ollama 是给个人用的,vLLM 是给生产用的。
1.2 PagedAttention:核心原理(面试必考)
定位清楚了,下面进入最关键的技术原理。PagedAttention 是 vLLM 性能碾压同类框架的根本原因,也是面试中被问到「vLLM 为什么快」时的标准答案。
这是 vLLM 最重要的技术创新,也是它碾压其他框架的根本原因。
传统 KV Cache 的问题
大模型在推理时,每个 token 生成都需要用到之前所有 token 的 Key/Value 矩阵(即 KV Cache)。传统做法是预先为每个请求分配一块连续的显存空间:
1 | 请求A: [████████████████████________] 预分配 2048 token 空间,实际用了 300 token |
这带来三个致命问题:
- 预分配浪费:不知道请求最终生成多长,只能按最大长度预留,大量空间闲置
- 碎片化严重:请求结束后释放的空间东一块西一块,无法被新请求利用
- 并发上限低:显存浪费 → 能同时处理的请求数极少 → 吞吐量低
典型数据:传统方式 KV Cache 显存利用率通常仅有 20%~40%,大量显存被浪费。
PagedAttention 解决方案:停车场类比
想象一个停车场管理系统:
- 传统方式:来了一辆车,先给它”预订” 10 个车位(因为不知道它会带几辆跟随车),哪怕最后只用了 2 个,剩下 8 个也空着等它。
- PagedAttention 方式:车位按需分配,用完一个再给一个,停车场利用率接近 100%。
技术层面的映射:
- 物理块(Physical Block):显存中固定大小的存储单元(类似停车位),每块存储固定数量 token 的 KV Cache(默认 16 个 token)
- 逻辑块(Logical Block):请求视角的连续地址空间(类似车牌号→车位号的映射表)
- 按需分配:请求每生成 16 个 token 才申请一个新物理块,不提前占用
- 共享机制:多个请求如果有相同前缀(如 System Prompt),可以共享同一组物理块,零拷贝复用
1 | 逻辑视图(请求A眼中): [Block 0][Block 1][Block 2]... |
为什么能提升 2-4x 吞吐量
| 维度 | 传统方式 | PagedAttention |
|---|---|---|
| 显存利用率 | 20%~40% | > 90% |
| 碎片化 | 严重 | 几乎为零 |
| 同时处理请求数 | 受限 | 大幅提升 |
| 前缀共享 | 不支持 | 支持(CoW 机制) |
显存利用率从 30% 提升到 90%,意味着同等显存能塞入的请求数提升了 3 倍,吞吐量自然随之提升。
1.3 Continuous Batching:连续批处理
PagedAttention 解决了「显存如何高效利用」的问题,但光有显存还不够——还要让 GPU 的计算单元永远不闲着。这就是 Continuous Batching 要解决的问题。
传统 Static Batching 的问题:
1 | Batch:[请求A-500token][请求B-50token][请求C-300token] |
请求 B 早就完成了,但 GPU 在傻等请求 A,这段时间 GPU 计算能力完全浪费。
Continuous Batching(vLLM 采用):
1 | 时刻1: [请求A][请求B][请求C] |
GPU 永远满载,空闲率趋近于零。这也是 vLLM 在高并发场景下吞吐量远超静态批处理框架的核心原因。
1.4 支持的模型格式
原理层面搞清楚了,最后补一个实用信息:vLLM 支持哪些模型格式。这直接决定你能不能把手头的模型加载进来。
| 格式 | 说明 | 典型场景 |
|---|---|---|
| FP16 / BF16 | 半精度浮点,精度最高 | A100/H100 高精度场景 |
| AWQ | 激活感知量化,4-bit,精度损失极小 | 显存受限 + 质量要求高 |
| GPTQ | 训练后量化,4-bit/8-bit | 模型丰富,选择多 |
| SqueezeLLM | 稀疏量化 | 研究场景 |
二、环境 & 前置依赖
原理搞清楚了,接下来搭环境。vLLM 对环境要求比 Ollama 严格不少,提前配对能省掉大量排错时间——尤其是 Windows 用户,这里有个天坑需要提前知道。
2.1 系统要求
先看硬性门槛,不满足就无法安装。
| 项目 | 要求 | 说明 |
|---|---|---|
| 操作系统 | Linux(首选)/ macOS(部分功能) | Windows 需通过 WSL2 或 Docker |
| Python | 3.9 ~ 3.12 | 推荐 3.10 / 3.11 |
| CUDA | 12.1 及以上 | CUDA 11.x 部分版本兼容,但不推荐 |
| GPU 驱动 | >= 525.x | nvidia-smi 确认 |
| 显存 | 最低 8GB VRAM | 7B FP16 需要 ~14GB,推荐 16GB+ |
Windows 用户注意:vLLM 不原生支持 Windows,必须使用 WSL2(Windows Subsystem for Linux)或 Docker。后文踩坑章节有详细方案。
2.2 推荐硬件配置
系统要求确认后,再对照自己的 GPU 档位,看能跑哪类模型。
| 场景 | 推荐 GPU | 可部署模型 |
|---|---|---|
| 个人开发测试 | RTX 3090/4090(24GB) | 7B FP16,13B AWQ |
| 团队服务 | A10G(24GB)× 1 | 7B FP16,13B AWQ/GPTQ |
| 企业生产 | A100(80GB)/ H100 | 70B FP16,各类量化大模型 |
| 多卡扩展 | 2-8 × A100 | 超大模型 Tensor Parallel |
2.3 CUDA 版本确认
硬件确认没问题后,最后一步是验证 CUDA 版本——这是 vLLM 安装失败的最高频原因,先查清楚再装。
1 | # 确认 CUDA 版本 |
三、Step-by-Step 实操流程
环境准备好了,正式进入动手环节。这一节按「安装 → 验证 → 启动服务 → 调用 → 高级用法」的顺序推进,每一步都可以独立复制执行,跟着走一遍就能跑通完整链路。
3.1 安装 vLLM
根据你的环境选择合适的安装方式,大多数情况下 pip 安装就够用,遇到版本冲突再考虑其他方式。
方式一:pip 安装(推荐,最简单)
1 | # 创建专用 conda 环境 |
方式二:指定 CUDA 版本安装
1 | # CUDA 12.1 |
方式三:Docker 安装(Windows / 环境隔离首选)
1 | # 拉取官方镜像(包含完整 CUDA 环境) |
方式四:源码编译(需要自定义 kernel 时使用)
1 | git clone https://github.com/vllm-project/vllm.git |
3.2 离线推理快速体验
安装成功后,不要急着上 API 服务,先用离线推理跑一把——这是最快的验证方式,能确认模型加载和 GPU 调用都正常,避免在 API 层排查时绕弯路。
安装完成后,先用 Python 脚本跑一下离线推理,验证环境是否正常:
1 | # offline_inference.py |
1 | python offline_inference.py |
看到模型输出即表示环境正常,可以进入下一步。
3.3 启动 OpenAI 兼容 API 服务
离线推理验证模型能正常工作后,下一步是把它包装成 API 服务——这才是生产场景的标准用法,也是后续所有调用示例的前提。
vLLM 内置了 vllm serve 命令,一行启动 OpenAI 兼容服务:
1 | # 基础启动 |
启动成功日志关键字:
1 | INFO: Started server process [xxxxx] |
3.4 API 调用验证
服务启动后,先用最简单的方式验证它真的在响应,再写复杂代码。养成「先 curl 验通,再写 SDK」的习惯能节省大量调试时间。
方式一:curl 验证
1 | # 查看可用模型 |
方式二:Python openai 库调用
1 | # api_call.py |
3.5 流式输出实现(完整示例)
同步调用验证没问题后,进入对话产品最常用的模式——流式输出。流式输出能让用户看到「打字机效果」,显著降低感知延迟,是生产环境的标配。
1 | # streaming_output.py |
3.6 加载量化模型(AWQ / GPTQ)
FP16 模型跑通了,但如果你的显存不够宽裕,或者想在同一张卡上多跑几个实例,就需要量化模型了。vLLM 对主流量化格式有原生支持,性能损失极小。
vLLM 对量化模型有原生支持,指定 --quantization 参数即可:
AWQ 模型(推荐,精度损失最小)
1 | # 启动 AWQ 量化模型 |
GPTQ 模型
1 | vllm serve /path/to/Qwen2.5-7B-Instruct-GPTQ-Int4 \ |
Python 离线加载量化模型
1 | from vllm import LLM, SamplingParams |
显存对比:7B FP16 约需 14GB,7B AWQ-4bit 约需 4-5GB,同一块 24GB 显卡 AWQ 可以多跑 2-3 个实例。
3.7 多 GPU 部署(Tensor Parallelism)
单卡跑通后,如果模型太大(如 70B)单卡放不下,或者需要更高的吞吐上限,就该上多卡并行了。vLLM 的 Tensor Parallelism 配置极简,加一个参数搞定。
当模型太大单卡放不下,或需要更高吞吐时,使用 Tensor Parallelism:
1 | # 2 卡并行(将模型张量切分到 2 张 GPU) |
Python 方式
1 | from vllm import LLM |
3.8 高并发压测脚本
多 GPU 配好后,是时候用数据验证一下 vLLM 的并发能力了。下面这个压测脚本可以直接跑,输出吞吐量和延迟分位数,让你直观感受到 PagedAttention + Continuous Batching 的效果。
用这个脚本模拟并发请求,直观看到 vLLM 的高吞吐能力:
1 | # benchmark_concurrent.py |
1 | pip install aiohttp |
3.9 与其他框架性能对比测试
自测脚本跑完有了直觉后,如果需要更标准化的对比数据,可以用 vLLM 官方的 benchmark 工具,复现社区公认的性能基准。
使用 vLLM 官方 benchmark 工具:
1 | # 安装 benchmark 依赖 |
四、关键参数详解
基本跑通之后,想要榨干性能、稳定服务就需要精细调参了。vLLM 的参数体系比较完整,这里按用途分组梳理,重点看性能参数和优化参数。
4.1 服务参数
这些是启动服务的基础配置,生产环境必须设置 --api-key,不然任何人都能调用你的服务。
1 | vllm serve <model_path_or_name> \ |
4.2 性能参数(重点)
这组参数直接决定服务能跑多快、能扛多高并发,也是遇到 OOM 时最先要动的地方。
1 | --tensor-parallel-size 2 \ # 多卡张量并行数,必须等于 GPU 数量 |
4.3 量化参数
如果你加载的是量化模型,或者想控制精度和加载速度,这里的参数需要配合使用。
1 | --quantization awq \ # 量化方式:awq / gptq / squeezellm / fp8 |
4.4 优化参数
这组参数是进阶调优的重点,尤其是 --enable-prefix-caching,在 RAG 和多轮对话场景下效果非常显著,强烈建议开启。
1 | --enable-prefix-caching \ # 开启前缀缓存(相同 System Prompt 的请求共享 KV Cache) |
4.5 参数调优速查
遇到具体问题不知道动哪个参数?查这张表,对症下药。
| 问题 | 调整参数 | 调整方向 |
|---|---|---|
| OOM / 显存溢出 | --gpu-memory-utilization |
降低(如 0.85→0.75) |
| OOM / 序列太长 | --max-model-len |
缩短(如 8192→4096) |
| 并发不足 | --max-num-seqs |
提高 |
| 首 token 延迟高 | --enable-chunked-prefill |
开启 |
| 多轮/RAG 场景 | --enable-prefix-caching |
开启 |
| 模型加载慢 | --load-format safetensors |
切换格式 |
五、性能对比数据
参数调好后,来看看 vLLM 相比其他框架到底快多少——用数据说话,不靠感觉。以下数据基于公开 Benchmark 报告和社区测试结果,标注为参考值/典型值,实际因硬件、模型、负载不同会有差异。
5.1 vLLM vs 其他框架吞吐量对比
先看最直观的横向对比:同样的硬件、同样的模型,各框架能跑多快?
测试环境:A100 80GB,Llama-2-13B FP16,并发 50,请求参数:输入 512 tokens,输出 256 tokens
| 框架 | 吞吐量(tokens/s) | P50 延迟 | P95 延迟 | 说明 |
|---|---|---|---|---|
| vLLM | ~4200 | ~1.2s | ~2.1s | PagedAttention + Continuous Batching |
| FastChat | ~1800 | ~2.8s | ~5.2s | HuggingFace Transformers 后端 |
| Text-Generation-WebUI | ~1200 | ~3.5s | ~7.0s | 单请求处理 |
| Ollama | ~900 | ~4.2s | ~9.0s | 面向个人使用,非并发优化 |
| llama.cpp(CPU) | ~150 | ~25s | ~50s | CPU 推理,低硬件门槛 |
结论:高并发场景下 vLLM 吞吐量是 Ollama 的 4-5 倍,是 FastChat 的 2-3 倍。
5.2 不同并发数下的 vLLM 表现
横向比完,再看 vLLM 自身在不同并发压力下的表现曲线——这组数据能帮你判断你的业务量级下 GPU 资源是否被充分利用。
测试环境:RTX 4090 24GB,Qwen2.5-7B-Instruct FP16,输出 200 tokens
| 并发数 | 吞吐量(tokens/s) | P50 延迟 | P95 延迟 | GPU 利用率 |
|---|---|---|---|---|
| 1 | ~150 | ~1.3s | ~1.5s | ~30% |
| 5 | ~650 | ~1.5s | ~2.0s | ~65% |
| 10 | ~1100 | ~1.8s | ~2.5s | ~85% |
| 20 | ~1600 | ~2.4s | ~3.5s | ~95% |
| 50 | ~1900 | ~4.5s | ~7.0s | ~98% |
规律:并发越高,吞吐量越大(GPU 越充分利用),但单请求延迟也随之增加。
5.3 gpu-memory-utilization 对并发上限的影响
并发曲线看完,再看一个关键调参项:--gpu-memory-utilization 设多少才合适?这组数据能给你一个直观参考。
测试:RTX 4090 24GB,7B FP16 模型
--gpu-memory-utilization |
可用 KV Cache 空间 | 最大并发序列数 | 说明 |
|---|---|---|---|
| 0.70 | ~4GB | ~30 | 保守,稳定优先 |
| 0.85 | ~7GB | ~60 | 推荐默认值 |
| 0.90 | ~9GB | ~80 | 生产推荐 |
| 0.95 | ~11GB | ~100 | 激进,有 OOM 风险 |
5.4 量化模型 vs FP16 在 vLLM 上的性能差异
最后一组数据:量化到底损失多少性能?这是很多人在「省显存」和「保精度」之间纠结时最需要的参考。
测试:A100 80GB,Qwen2.5-7B,并发 20
| 模型精度 | 显存占用 | 吞吐量(tokens/s) | 精度损失 | 推荐场景 |
|---|---|---|---|---|
| FP16 | ~14GB | ~2200 | 无 | 精度要求高 |
| BF16 | ~14GB | ~2400 | 极小 | A100/H100 首选 |
| AWQ-4bit | ~4.5GB | ~1900 | 极小(<1%) | 显存受限首选 |
| GPTQ-4bit | ~4.5GB | ~1700 | 小(~1-2%) | 模型丰富时使用 |
| GPTQ-8bit | ~8GB | ~2000 | 极小 | 精度/显存平衡 |
六、踩坑记录 & 问题解决
性能虽好,但 vLLM 的部署门槛比 Ollama 高不少,坑也集中在环境配置和显存管理上。以下是实际部署中最高频的问题,遇到直接对号入座。
坑1:Windows 不支持,安装直接报错
症状:pip install vllm 在 Windows PowerShell 中报编译错误,提示缺少 Linux 相关头文件。
原因:vLLM 依赖 Linux 特有的 CUDA 接口和内存管理机制,不支持原生 Windows。
解决方案:
1 | # 方案一:使用 WSL2(推荐) |
坑2:CUDA 版本不匹配导致安装失败
症状:pip install vllm 完成但 import vllm 报 CUDA error 或 undefined symbol。
排查步骤:
1 | # 查看系统 CUDA 版本 |
坑3:OOM(显存溢出)
症状:启动时报 CUDA out of memory 或运行中突然崩溃。
排查与解决:
1 | # 方法1:降低显存利用率(最直接) |
显存需求速查表:
| 模型 | FP16 显存 | AWQ-4bit 显存 |
|---|---|---|
| 7B | ~14GB | ~5GB |
| 13B | ~26GB | ~8GB |
| 34B | ~68GB | ~20GB |
| 70B | ~140GB(需多卡) | ~40GB |
坑4:模型加载极慢
症状:vllm serve 启动后长时间停在 Loading model weights...,超过 5 分钟。
原因与解决:
1 | # 原因1:模型文件是 .bin 格式(PyTorch 旧格式),加载慢 |
坑5:某些模型不支持(架构未适配)
症状:报 ValueError: Model architectures ['XxxForCausalLM'] are not supported。
解决:
1 | # 查看 vLLM 支持的所有模型架构 |
坑6:流式输出卡顿或中断
症状:stream=True 时,输出一半就停了,或者 chunk 很久才来一个。
排查:
1 | # 检查是否有超时设置 |
七、场景适配 & 优劣分析
了解了 vLLM 的能力边界和常见坑点后,最后做个收尾——什么时候该用 vLLM,什么时候换其他方案,用决策逻辑而不是感觉来选型。
7.1 什么时候该用 vLLM
vLLM 的最佳战场:
| 场景 | 说明 |
|---|---|
| 高并发 API 服务 | 10+ 并发请求,vLLM 吞吐量远超其他方案 |
| 企业级生产部署 | 需要稳定性、监控、OpenAI 兼容接口 |
| 资源最大化利用 | 贵的 GPU(A100/H100),不能让它闲着 |
| 多用户场景 | 团队共用模型服务器,多人同时调用 |
| RAG / 知识库场景 | prefix caching 大幅降低重复 System Prompt 的开销 |
7.2 什么时候不该用 vLLM
知道该用的场景,同样重要的是知道不该强行上 vLLM 的场景,避免用锤子找钉子。
| 场景 | 推荐替代 | 原因 |
|---|---|---|
| CPU 推理 | llama.cpp | vLLM 只支持 NVIDIA GPU |
| 低显存设备(<8GB) | llama.cpp / Ollama | 最低显存要求较高 |
| Windows 原生 | Ollama | vLLM 不支持 Windows |
| 快速个人测试 | Ollama | vLLM 环境配置复杂 |
| 调试/可视化 | Text Generation WebUI | vLLM 无 GUI |
7.3 框架终极对比
适用场景有了感知后,再用一张完整的横向对比表,把系列里出现的所有框架放在一起,一眼看出各自的位置。
| 维度 | Ollama | llama.cpp | Text-Gen-WebUI | FastChat | vLLM |
|---|---|---|---|---|---|
| 上手难度 | ⭐(最简单) | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 高并发性能 | ⭐⭐ | ⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 显存利用率 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Windows 支持 | ✅ | ✅ | ✅ | ✅ | ❌(需 WSL2) |
| CPU 推理 | ✅ | ✅ | ✅ | ⚠️ | ❌ |
| OpenAI 兼容 | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| 生产就绪 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
7.4 什么时候该从 Ollama 迁移到 vLLM
很多团队是从 Ollama 起步的,迁移到 vLLM 是个很常见的演进路径。下面给出明确的迁移触发条件,不需要主观判断,对号入座就行。
以下任意一条成立,就该考虑迁移:
- 并发用户数 持续超过 5 人
- 接口 P95 延迟 超过业务容忍上限(通常 3-5 秒)
- GPU 利用率 低于 60%(资源浪费)
- 业务要求 精确的 Token 级计费或限流
- 需要同时管理 多个版本模型的灰度发布
迁移成本低:vLLM 完全兼容 OpenAI 接口,代码层面只需把
base_url从 Ollama 的端口改为 vLLM 的端口,业务代码零修改。
八、本篇小结
跑完这一套下来,对 vLLM 的掌握程度应该已经从「听说过」升级到「能用、会调、会讲原理」了。这里做一个系统性的收尾,方便后续快速复习。
8.1 核心知识点复盘
| 知识点 | 核心要点 |
|---|---|
| PagedAttention | 操作系统分页内存管理思想 → 按需分配 KV Cache 物理块,显存利用率从 30% → 90% |
| Continuous Batching | 请求完成立即补位,GPU 永远满载,对比静态批处理吞吐量提升 2-5x |
| 量化支持 | AWQ 精度损失最小,GPTQ 模型最丰富,FP16/BF16 精度最高 |
| 多卡并行 | --tensor-parallel-size N,模型张量切分到 N 张 GPU |
| 前缀缓存 | --enable-prefix-caching,相同 System Prompt 共享 KV Cache,RAG 必开 |
8.2 命令速查表
知识点复盘完,这里把全文最常用的命令集中整理,方便后续使用时快速查找,不用再翻全文。
1 | # 安装 |
8.3 PagedAttention 面试回答模板
命令速查备用,最后是这篇文章含金量最高的部分——PagedAttention 的面试标准答案。无论是 30 秒快问还是 2 分钟深聊,下面两个版本都能覆盖。
30 秒版(适合简历筛选、电话面试)
PagedAttention 是 vLLM 提出的 KV Cache 管理机制,核心思想借鉴操作系统的虚拟内存分页管理。传统方案会为每个请求预先分配一大块连续显存存 KV Cache,导致大量空间浪费,显存利用率只有 20-40%。PagedAttention 将 KV Cache 切成固定大小的物理块,按需分配,用一个映射表维护逻辑地址到物理块的对应关系,使显存利用率提升到 90% 以上,从而让同等显存能服务更多并发请求,整体吞吐量提升 2-4 倍。
2 分钟版(适合技术面试深问)
PagedAttention 解决的核心问题是:LLM 推理时 KV Cache 占用显存的低效问题。
背景:大模型自回归生成时,需要缓存所有历史 token 的 Key/Value 矩阵(即 KV Cache)。传统实现中,每个请求在启动时就预分配一块连续的最大显存空间(比如 2048 token 对应的空间),但实际上很多请求可能只生成 200 token 就结束了,剩余空间完全浪费。加上请求结束后释放的碎片化空间,整体利用率只有 20-40%。
PagedAttention 的解决思路:把 KV Cache 切分成固定大小的物理块(默认 16 token/块),类似操作系统的内存页。每个请求维护一张逻辑块号→物理块号的映射表(类似页表),按需申请物理块,请求生成 16 个 token 才申请一个新块,不提前占用。此外,有相同前缀(如相同 System Prompt)的多个请求可以共享同一组物理块,进一步减少显存占用。
效果:显存利用率从 20-40% 提升到 90% 以上,同等显存下并发请求数大幅提升,配合 Continuous Batching(请求完成立即补位),整体吞吐量提升 2-4 倍,这是 vLLM 在高并发场景下碾压其他框架的根本原因。
8.4 选型决策树
面试模板之后,用这棵决策树给本篇画上句号:拿到任何一个部署需求,顺着分支往下走,终点就是最合适的方案。
1 | 有 GPU 且需要对外提供 API 服务? |
本文为「本地大模型部署系列」第8篇,完整系列持续更新中。