vLLM Deep Dive Part 1: Architecture Overview
第一部分:vLLM 架构概览
简介
在深入研究具体组件之前,我们需要先了解 vLLM 的整体架构。本文梳理了各主要组件及其交互方式,为后续各部分的深入探讨奠定基础。
全局视角
vLLM 的设计围绕以下几个核心原则:
- 关注点分离:不同职责(调度、执行、服务)由各自独立的组件负责处理
- 进程隔离:V1 架构采用多进程设计,以提升健壮性和 CPU 利用率
- 异步处理:请求在流水线中流转,不会产生阻塞
- 默认分布式:从底层设计上即支持多 GPU 执行
高层数据流
当你向 vLLM 发送一个请求时,整个流程如下:
1 | User Request (HTTP/gRPC) |
V1 多进程架构
V1 架构(于 2024 年底引入)采用多进程设计,以实现更好的 CPU 利用率和进程隔离。下面逐一介绍各进程类型:
1. API Server 进程
职责:处理 HTTP/gRPC 请求及 I/O 操作
主要任务:
- 接收并校验 HTTP 请求
- 对输入文本进行 tokenize
- 加载多模态数据(图像、音频)
- 将输出以流式方式返回给客户端
- 处理 API 鉴权与限流
核心实现:vllm/entrypoints/openai/api_server.py
API server 对于模型执行而言是无状态的。它不了解 GPU 内存、KV cache 或模型权重,只负责:
- 将用户请求转换为
EngineCoreRequest对象 - 通过 ZMQ 将其发送给 engine core
- 接收返回的
EngineCoreOutput对象 - 将其转换为 API 响应
进程数量:默认为 1 个 API server。启用 data parallelism(--data-parallel-size N)后,自动扩展至 N 个 API server。
CPU 线程:使用 VLLM_MEDIA_LOADING_THREAD_COUNT 个线程(默认 8)并行加载媒体文件。
2. Engine Core 进程
职责:调度请求并协调模型执行
主要任务:
- 维护请求队列
- 运行 scheduler 以决定计算内容
- 管理 KV cache 分配
- 协调 GPU worker
- 处理请求抢占与换出
核心实现:vllm/v1/engine/core.py
engine core 运行一个紧凑的循环(run_busy_loop,core.py:1138):
1 | def run_busy_loop(self): |
进程数量:每个 data parallel rank 对应一个。设置 --data-parallel-size 4 时,将启动 4 个 engine core。
CPU 用量:运行忙循环以实现低延迟的调度决策。
3. GPU Worker 进程
职责:在 GPU 上执行模型前向传播
主要任务:
- 将模型权重加载到 GPU
- 执行前向传播
- 管理 GPU 内存
- 运行 CUDA kernel(attention、FFN 等)
- 参与集合通信操作(用于 tensor parallelism / pipeline parallelism)
核心实现:vllm/v1/worker/gpu_worker.py
每个 GPU 都有其专属的 worker 进程。worker 负责:
- 加载其对应分片的模型权重
- 从对应的 engine core 接收执行请求
- 运行模型前向传播
- 返回输出结果(logits、KV cache 更新)
进程数量:每个 GPU 一个。对于 8 个 GPU,设置 --tensor-parallel-size 4 --data-parallel-size 2 时:
- 共 8 个 GPU worker
- 分为 2 组,每组 4 个(tensor parallel 分组)
- 2 个 engine core(每个 data parallel rank 各一个)
4. DP Coordinator 进程(按需启动)
职责:协调 data parallel 引擎
主要任务:
- 在 data parallel rank 之间进行负载均衡
- 同步 MoE 模型执行
- 将请求路由至负载最低的引擎
核心实现:vllm/v1/engine/coordinator.py
进程数量:当 --data-parallel-size > 1 时启动 1 个,否则不启动。
进程数量示例
下面来看几个具体示例:
示例 1:单 GPU
1 | vllm serve meta-llama/Llama-3-8B |
进程:
- 1 个 API Server
- 1 个 Engine Core
- 1 个 GPU Worker
- 共计:3 个进程
示例 2:Tensor Parallelism(4 个 GPU)
1 | vllm serve meta-llama/Llama-3-70B --tensor-parallel-size 4 |
进程:
- 1 个 API Server
- 1 个 Engine Core
- 4 个 GPU Worker(每个 GPU 各一个)
- 共计:6 个进程
示例 3:Data Parallelism(4 个 GPU)
1 | vllm serve meta-llama/Llama-3-8B --data-parallel-size 4 |
进程:
- 4 个 API Server(随 data parallelism 扩展)
- 4 个 Engine Core(每个 DP rank 各一个)
- 4 个 GPU Worker(每个 GPU 各一个)
- 1 个 DP Coordinator
- 共计:13 个进程
示例 4:混合并行(8 个 GPU)
1 | vllm serve meta-llama/Llama-3-70B --tensor-parallel-size 2 --data-parallel-size 4 |
进程:
- 4 个 API Server
- 4 个 Engine Core(每个 DP rank 各一个)
- 8 个 GPU Worker(每个 DP rank 2 个,每个 GPU 各一个)
- 1 个 DP Coordinator
- 共计:17 个进程
核心组件详解
LLMEngine
LLMEngine 类是离线推理(直接使用 Python API)的主要入口点。
位置:vllm/v1/engine/llm_engine.py
主要职责:
- 创建并管理 engine core
- 通过
InputProcessor处理输入 - 通过
OutputProcessor转换输出 - 管理请求生命周期
使用示例:
1 | from vllm import LLM, SamplingParams |
在底层,LLM 创建 LLMEngine,LLMEngine 再创建 EngineCore,由其协调各 worker。
Scheduler
Scheduler 是 vLLM 的核心大脑,负责决策:
- 每次迭代处理哪些请求
- 每个请求计算多少 token
- 何时以及对哪些请求进行抢占
- 如何分配 KV cache 块
位置:vllm/v1/core/sched/scheduler.py
Scheduler 维护三个队列:
- 等待队列(Waiting):等待开始处理的新请求
- 运行队列(Running):正在被处理的请求
- 暂跳队列(Skipped Waiting):因依赖关系而被临时跳过的请求
调度算法(简化版):
1 | def schedule(self) -> SchedulerOutput: |
我们将在第三部分深入探讨 scheduler。
KV Cache Manager
使用 PagedAttention 管理 attention key-value cache 的内存。
位置:vllm/v1/core/kv_cache_manager.py
核心概念:
- Block(块):固定大小的 KV cache 单元(例如 16 个 token)
- Block Pool(块池):预分配的块集合
- Block Table(块表):逻辑位置到物理块的映射
- Prefix Cache(前缀缓存):用于共享公共 prompt 前缀的块
示例:若块大小为 16,共有 1000 个块,则可以服务于:
- 1 个拥有 16,000 个 token 的请求,或
- 16 个各有 1,000 个 token 的请求,或
- 任何能放入 1000 个块的组合
我们将在第二部分深入剖析 PagedAttention。
Worker 与 ModelRunner
worker 进程负责加载模型并执行前向传播。
Worker(vllm/v1/worker/gpu_worker.py):
- 管理 GPU 设备
- 初始化模型权重
- 与其他 worker 协调(用于 tensor parallelism / pipeline parallelism)
ModelRunner(因后端而异):
- 准备输入 tensor
- 执行模型前向传播
- 应用 CUDA graph 优化
- 返回输出 logits
请求生命周期
让我们跟踪一个完整请求在系统中的流转过程:
1. 请求到达
1 | POST /v1/completions |
2. API Server 处理
- 校验请求
- 对 prompt 进行 tokenize:
[791, 3139, 315, 9822, 374] - 创建
EngineCoreRequest对象 - 通过 ZMQ 发送至 engine core
3. Engine Core 接收
- 将请求加入 scheduler 的等待队列
- 分配请求 ID:
"req_abc123" - 初始化请求状态
4. 首次调度迭代
- Scheduler 发现等待队列中的新请求
- 检查 KV cache:5 个 token 需要计算
- 分配 KV cache 块(块大小为 16 token 时,分配 1 个块)
- 调度 prefill:计算全部 5 个 token
5. Worker 执行
- 从 engine core 接收调度指令
- 准备输入 tensor
- 运行模型前向传播
- 生成第一个 token(例如,token ID 330 = “Paris”)
- 将 logits 返回给 engine core
6. 输出处理
- Engine core 接收 logits
- 采样下一个 token:330(”Paris”)
- 更新请求状态:将 token 追加到输出中
- 通过 ZMQ 将输出发送给 API server
7. API Server 流式输出
- 从 engine core 接收 token
- Detokenize:”Paris”
- 流式返回给客户端:
data: {"text": "Paris", "finish_reason": null}
8. 后续迭代
- 请求移入运行队列
- Scheduler 持续分配 token
- 每次迭代:计算 1 个新 token(decode 阶段)
- 将每个 token 流式发送给客户端
9. 请求完成
- 达到 max_tokens 上限或生成 EOS
- 释放 KV cache 块(或保留在 prefix cache 中)
- 向客户端发送最终完成结果
- 从 scheduler 中移除请求
配置与初始化
vLLM 的配置统一集中在 VllmConfig 中:
1 | from vllm.config import VllmConfig |
所有组件共享同一个 VllmConfig 对象,以确保一致性。
主要配置项:
- ModelConfig:模型名称、dtype、tokenizer
- CacheConfig:KV cache 大小、块大小、prefix caching
- SchedulerConfig:最大批量大小、调度策略
- ParallelConfig:TP/PP/DP 规模、分布式后端
类层次结构
类层次结构遵循一致的模式:
1 | LLMEngine |
每个类在其构造函数中均接受 VllmConfig,从而可以访问所有配置选项。
进程间通信
ZMQ Sockets
API server 与 engine core 通过 ZMQ 进行通信:
1 | # API Server side |
为什么选择 ZMQ?
- 高性能(微秒级延迟)
- 灵活的通信模式(req-rep、pub-sub、push-pull)
- 内置队列管理
- 语言无关
NCCL 用于 GPU 通信
GPU worker 使用 NCCL 进行集合通信操作:
1 | # Tensor parallelism: all-reduce across GPUs |
通信模式:
- Tensor Parallel:在 attention/FFN 之后执行 All-reduce
- Pipeline Parallel:各阶段之间执行发送/接收操作
- Data Parallel:前向传播期间无需通信
内存布局
理解内存布局对于 vLLM 至关重要:
GPU 内存分布
1 | Total GPU Memory: 80GB (H100) |
KV Cache 内存
对于块大小为 16 token 的 8B 模型:
- 每个块存储 32 个 attention 层的 K 和 V
- 每块大小:16 token × 32 层 × 2(K,V)× 4096 维 × 2 字节 = 8.4 MB
- 若 KV cache 分配 60GB:约 7,100 个块
- 总容量:跨所有请求约 113,600 个 token
性能特征
H100 GPU 上的典型性能表现:
| 指标 | 数值 |
|---|---|
| 吞吐量(Throughput) | ~8,000 tokens/sec(Llama-3-8B) |
| 延迟(TTFT) | ~20-50ms |
| 延迟(TPOT) | ~10-15ms |
| 最大批量大小(Max Batch Size) | ~256 并发请求 |
| 内存效率(Memory Efficiency) | ~95%(相比不使用 PagedAttention 时的 ~60%) |
下一步
现在我们已经了解了整体架构,接下来可以深入探讨各具体组件:
- 第二部分:PagedAttention 与 KV cache 管理
- 第三部分:Scheduler 的决策过程
- 第四部分:请求处理与状态管理
- 第五部分:分布式执行与并行策略
关键要点
- V1 采用多进程架构,以提升 CPU 利用率和故障隔离能力
- Scheduler 是核心协调者,负责决策每次迭代的计算内容
- KV cache 管理(PagedAttention)是内存效率的关键所在
- 进程数量随并行度扩展:通常为
API server 数 + Engine core 数 + GPU worker 数 +(可选的 DP Coordinator) - ZMQ 实现了高效的进程间通信
- 所有组件共享统一的
VllmConfig,确保一致性
参考资料
在下一篇文章中,我们将详细探讨 PagedAttention,了解 vLLM 如何通过精巧的内存管理实现近乎零浪费的内存利用。