
从0开始的vLLM学习
文章结构(五大部分)
1. LLM Engine & Engine Core(核心引擎)
Engine 构造函数的四大组件:
- vLLM Config:所有配置(模型、cache、并行度等)
- Processor:原始输入 →
EngineCoreRequest(tokenize + 校验) - Engine Core Client:单进程下 ≈
EngineCore,分布式下是DPLBAsyncMPClient - Output Processor:原始输出 → 用户看到的
RequestOutput
Engine Core 内部:
- Model Executor(
UniProcExecutor→MultiProcExecutor) - Scheduler(FCFS or Priority,含 waiting/running 两个队列)
- KV Cache Manager(PagedAttention 的核心,管理
free_block_queue)
Worker 初始化三步走:init_device → load_model → init_kv_cache(包含 profile run 计算可用 blocks,以及 CUDA Graph 预热)
每个 Step 三阶段:Schedule → Forward Pass → Postprocess
Scheduler 的调度逻辑:
- 优先处理
running队列(decode 请求) - 再处理
waiting队列(prefill 请求) allocate_slots负责从free_block_queue里实际分配 KV cache block
2. Advanced Features(高级特性)
[table]
3. 从 UniProcExecutor 到 MultiProcExecutor(多 GPU 扩展)
MultiProcExecutor用共享内存rpc_broadcast_mq广播任务给各 worker 进程- 每个 worker 独立执行 init → load → kv_cache 三步,通过 TP/PP 分片协作
- 对上层 Engine 完全透明
4. 分布式 Serving 层
完整的请求生命周期:
curl /v1/completions
→ FastAPI (Uvicorn)
→ OpenAIServingCompletion
→ AsyncLLM.generate
→ DPLBAsyncMPClient(负载均衡:score = waiting*4 + running)
→ DPEngineCoreProc(input thread → main thread → output thread)
→ MultiProcExecutor → Worker(TP=4)
→ 结果原路返回
DP Coordinator 负责各引擎的负载均衡状态同步,支持弹性扩缩容(Ray 后端)。
5. Benchmarks & 性能指标
关键指标:TTFT、ITL、TPOT、E2E Latency、Throughput、Goodput
Roofline 模型:
- Batch size 小 → memory-bandwidth bound → ITL 低但吞吐差
- Batch size 大 → compute bound → 吞吐高但 ITL 上升
- 两者天然对立,
B_sat是拐点
LLM Engine & Engine Core
Engine
- vLLM config:所有配置(模型/cache/并行度等)
模型:
chche:
并行度
- Processor(类似于点单员,把用户的需求转化成厨房能懂的格式):
原始输入->EngineCoreRequest(tokenize+校验)
tokenize: 把一段文本拆分成一个个“token” (最小的处理单元)详解
校验:审核格式,审核token长度(是否会超过 max_model_len ) 避免 KV cache 越界或 OOM ( Out Of Memory(内存不足) ),校验tokenizer和模型是否匹配,参数合法性校验(temperature,max_tokens),多模态对齐校验(prompt里的image 的token,( prompt: "Describe this <image>" )是否和实际传入的的图片数量匹配)
- Engine Core Client:单进程:EngineCore,分布式是 DPLBAsyncMPClient
- Output Processor(服务员,把东西处理好端给顾客): 原始输出 → 用户看到的
RequestOutput
Engine Core
- Model Executor(干活的)
- GPU Worker(干活的)
- Scheduler(调度员,决定做那些菜)
- KV Cache Manager(PagedAttention的核心,管理free_block_queue)
KV Cache:可以想象为提前的备菜
实际上的作用,在初始化的时候提前把一大块显存切分成小池子,传统方法预留一大块显存会很浪费空间,但使用KV Cache的时候可以按需分配显存,当需要的时候再把显存分给他,就可以在固定的显存范围内容纳更多的请求
Worker 初始化三步走:init_device → load_model → init_kv_cache(包含 profile run 计算可用 blocks,以及 CUDA Graph 预热)
init_device:绑定 CUDA 设备,检查 VRAM 够不够,初始化 model_runner(存放前向传播所需的 buffer)
load_model:加载模型权重,调用 model.eval(),可选跑 torch.compile()
init_kv_cache:这步最有意思——先跑一次"假的"前向传播来量一下 GPU 内存占用,然后算出剩余 VRAM 能放多少个 KV cache block,分配这些 block,最后预热 CUDA Graph(把常用 batch size 的计算图提前录制好,推理时直接 replay,省掉 kernel launch 开销)
每条 prompt 会被包装成一个 Request 对象,状态设为 WAITING,扔进 Scheduler 的 waiting 队列。
反复调用 step()
只要还有请求没处理完,引擎就一直循环,每次 step 分三阶段:
每个 Step 三阶段:Schedule → Forward Pass → Postprocess
Scheduler:最关键的部分
两种请求类型
Prefill(预填充):第一次处理一个请求,需要把完整的 prompt 全部过一遍模型,计算量大,是 compute-bound。结束时采样出第一个输出 token。
过一遍模型指的是算一遍qkv,
Decode(解码):后续每一步只输入最新的一个 token,因为之前的 token 的 KV 已经缓存了。每步计算量很小,但要把所有权重和 KV cache 从显存里读出来,是 memory-bandwidth-bound。
Scheduler 的调度逻辑:
- 优先处理
running队列(decode 请求) - 再处理
waiting队列(prefill 请求) allocate_slots负责从free_block_queue里实际分配 KV cache block