大数跨境

一文讲透 vLLM 核心架构:API Server、EngineCore、Scheduler、GPU Worker 如何协作

一文讲透 vLLM 核心架构:API Server、EngineCore、Scheduler、GPU Worker 如何协作 魔方AI空间
2026-11-01
4
导读:沿一次请求的完整路径,拆解 API Server、EngineCore、Scheduler 和 GPU Worker 的职责与协作关系

【从零走向AGI】旨在深入了解通用人工智能(AGI)的发展路径,从最基础的概念起,逐步构建完整的知识体系。

项目地址🔗:https://ai-mzq.github.io/From-Zero-to-AGI/[1]

欢迎关注【魔方AI空间】👇

AIGC技术交流社区(涵盖AI绘画、AI视频、大模型、AI多模态、数字人、具身智能等AIGC干货资源及教程)

往期推荐:

  • 一文讲透 AI 算力平台 8 个核心概念:GPU、显存、NVLink、InfiniBand、调度、存储、容器、监控
  • 一文详解大模型 12 个核心机制:Token、Embedding、Attention、Transformer、MoE、预训练、后训练、对齐、RAG、工具调用、推理、评测
  • 一文讲透大模型推理服务 8 个核心指标:TTFT、TPOT、ITL、端到端延迟、吞吐、并发、请求率与 Goodput

本文聚焦于 vLLM v0.31.0 的 V1 在线服务架构,沿一次请求的完整路径,拆解 API Server、EngineCore、Scheduler 和 GPU Worker 的职责与协作关系。

vLLM 迭代较快,后续版本的类名、进程拓扑或默认行为可能继续调整。本文涉及的当前实现,以 v0.31.0 官方文档和对应 tag 源码为准。

向 vLLM 发出一条流式请求后,客户端看到的过程很简单:连接建立,首个 token 返回,文字继续出现,直到生成结束。

如果首 token 迟迟不来,很多人的第一反应是 GPU 太慢。但此时,请求可能还没有到达 GPU。它也许正在 API Server 中等待输入处理,也许已经进入 EngineCore,却暂时拿不到足够的 token 预算或 KV Cache。

实际上,一次请求会穿过多个进程,并在多轮调度和模型执行中逐步向前推进。整条请求路径如图 1 所示。

图 1:一条在线请求穿过 vLLM V1 的完整路径

图 1:一条在线请求从 Client 进入 API Server,经 EngineCore 调度和 GPU Worker 执行,再由 OutputProcessor 返回客户端。

图里需要留意的是 EngineCore 与 GPU Worker 之间的往返。一个 HTTP 请求,通常会经历多轮调度和模型执行。

这条路径可以归结为三个问题:数据从哪里进出,谁决定下一轮计算什么,谁真正把计算送上 GPU。

01 从 V0 到 V1:核心架构演进

搜索 vLLM 架构资料时,经常会遇到互相对不上的类名。

有的文章围绕 LLMEngine 和 AsyncLLMEngine 展开,有的已经出现 AsyncLLM、EngineCore 和 EngineCoreClient;旧版中的 Scheduler 路径和当前源码也不完全相同。

这背后是 vLLM 核心架构从 V0 到 V1 的演进。

vLLM V1 官方指南[2]给出的背景是:V0 支持的模型、硬件和功能越来越多,不同能力独立演进,核心系统也逐渐变得复杂。V1 保留了模型实现、GPU kernels 和通用工具等成熟部分,同时重构 Scheduler、KV Cache Manager、Worker、Sampler 和 API Server 等核心系统。

V1 官方架构博客[3]提到一个关键变化:EngineCore 的执行循环被隔离出来,让 tokenization、多模态处理、detokenization 和响应流式返回等 CPU 工作,可以与核心调度和模型执行重叠。

到本文采用的 v0.31.0,官方文档已经明确标注 V0 被完全弃用。后文只分析 V1,V0 在这里主要用于解释旧教程和当前实现为什么会有差异。

本文关注 vllm serve 启动的在线文本生成服务,以及常见的 GPU multiprocessing 部署。离线 LLM、Ray、多节点和解耦式 Prefill/Decode 可能改变部分调用与启动方式,不在这里展开。

V0 到 V1 的保留与重构关系如图 2 所示。

图 2:V0 到 V1 的保留与重构

图 2:V1 并非把 V0 全部推倒重来,而是在保留模型与 GPU kernels 等成熟部分的同时重构核心组件。

02 V1 进程架构图:API Server、EngineCore 与 GPU Worker

根据 v0.31.0 Architecture Overview[4],V1 在线服务采用多进程架构。最主要的三个角色是 API Server、EngineCore 和 GPU Worker;使用数据并行时,还会出现 DP Coordinator。

角色
主要职责
容易产生的误解
API Server
HTTP 协议、输入处理、结果流式返回
只是一个反向代理
EngineCore
请求状态、调度循环、缓存协调、执行编排
就是模型或 GPU 进程
Scheduler
分配本轮 token 与 KV Cache 资源
负责执行模型 forward
GPU Worker
模型加载、设备内存、前向计算与采样
自己决定全局请求优先级

API Server 负责请求的进出。它接收 OpenAI-compatible HTTP 请求,处理 tokenization、多模态数据加载等输入工作,再把结果流式返回客户端。API Server 通过 ZMQ 与 EngineCore 通信。多个 API Server 和多个 EngineCore 同时存在时,官方架构采用 many-to-many 连接,并非永久绑定的一对一关系。

EngineCore 负责组织每一轮执行。它运行 Scheduler,协调 KV Cache 管理和模型执行,并通过持续运行的核心循环推进请求。通常每个 data-parallel rank 对应一个 EngineCore。

GPU Worker 负责设备侧计算。在官方描述的标准 GPU 部署中,每张 GPU 由一个 Worker 进程管理。Worker 加载模型权重、管理 GPU 内存、执行模型前向,并与其他 Worker 协作完成张量并行或流水线并行。

当 DP > 1 时,系统还会增加一个 DP Coordinator,负责 DP rank 之间的负载协调,并在 MoE 等场景中协调同步前向。

这些进程的连接关系如图 3 所示。

图 3:vLLM V1 标准在线服务进程拓扑

图 3:API Server 与 EngineCore 通过 ZMQ 建立 many-to-many 连接,每个 EngineCore 再管理自己的 GPU Worker 组。

进程和模块也要分开理解。Scheduler 是 EngineCore 内部的关键决策模块,通常不会作为与 EngineCore 并列的服务进程存在;Executor 位于 EngineCore 与 Worker 之间,负责把执行调用送到具体 Worker。

03 API Server:请求到达 GPU 之前,还要做什么

API Server 承担的工作远不止 HTTP 转发。

以 Chat Completions 请求为例,客户端发来的是 messages、模型名、采样参数、停止条件以及 stream 等协议字段。API Server 需要完成请求校验、Chat 模板渲染和输入预处理,再把文本转换成模型能够处理的 token。

如果请求中包含图片、音频或视频,前端还可能承担媒体读取和预处理。因此,多模态请求让 GPU 空闲,并不一定说明 GPU 执行效率低,瓶颈可能发生在请求进入 EngineCore 之前。

在 V1 在线路径中,API Server 会构建 AsyncLLM。它把处理后的输入转换成内部请求,同时为每条在线请求维护异步输出消费路径。跨越进程边界的连接,由 EngineCoreClient 抽象完成。

EngineCoreClient 官方 API 文档[5]列出了不同使用方式:同步多进程客户端可以服务离线 LLM,asyncio-compatible 的 AsyncMPClient 则用于 AsyncLLM。在在线多进程路径里,它通过输入通道发送 EngineCoreRequest,再从输出通道接收 EngineCoreOutputs。

API Server 的输入与输出双向路径如图 4 所示。

图 4:API Server 的输入与输出双向路径

图 4:API Server 一边完成协议校验、模板处理和 tokenization,一边接收 EngineCore 输出并组织流式或非流式响应。

扩容 API Server 增加的是前端连接、输入处理和结果返回能力,不会直接增加某个模型副本的 GPU 算力。反过来,如果 API Server 的 CPU 资源不足,后面的 GPU 即使有空闲,也可能吃不到足够快的请求。

04 EngineCore:请求为什么会反复进入执行循环

请求进入 EngineCore 后,不会被一次性交给 GPU 算到结束。

自回归模型每生成新的 token,都要基于已有上下文再次执行模型。Orca[6]曾把这种负载概括为具有多轮迭代特征,并提出 iteration-level scheduling:调度粒度可以是模型的一次迭代,而不是整条请求。

vLLM V1 的实现并不等同于 Orca,但“请求会反复进入执行迭代”是理解 EngineCore 的关键。长短不同的请求可以动态组成 batch,系统也需要持续维护每条请求的状态。

EngineCore 主要负责:

· 接收新的 EngineCoreRequest,并交给 Scheduler;

· 持有 Scheduler、模型 Executor 及相关管理组件;

· 根据 Scheduler 的结果触发模型执行;

· 把模型输出反馈给 Scheduler,更新请求和缓存状态;

· 处理完成、取消、错误和部分运行时控制请求。

EngineCore 的 v0.31.0 源码[7]中,核心关系可以压缩为下面这段结构化伪代码:

while has_work:
    scheduler_output = scheduler.schedule()
    model_output = model_executor.execute_model(scheduler_output)
    engine_core_outputs = scheduler.update_from_output(
        scheduler_output,
        model_output,
    )

这段伪代码保留了三步关键动作:

1. schedule:决定本轮让哪些请求推进多少 token;

2. execute_model:把执行计划交给 Worker;

3. update_from_output:依据模型结果更新请求与缓存状态。

请求没有结束,就会继续参加后续迭代;新请求也可以在新的迭代中加入。这是连续批处理能够动态调整 batch 的基础之一。

EngineCore 的核心循环如图 5 所示。

图 5:EngineCore 迭代循环

图 5:EngineCore 按照 schedule、execute_model、update_from_output 的顺序反复推进请求,直到满足结束条件。

EngineCore 的循环越紧凑,两个模型前向之间留下的 CPU 空隙就越小。GPU 越快、模型单轮执行时间越短,CPU 调度、输入准备和输出处理的影响越明显。官方调优文档[8]因此会单独讨论 GPU 部署所需的 CPU 资源。

05 Scheduler:每一轮究竟让谁计算多少 token

Scheduler 的工作不止是决定请求的先后顺序。

V1 Scheduler 要在有限 token 预算和 KV Cache 下,决定这一轮哪些请求各处理多少 token。

它需要同时考虑:

· 哪些请求正在 waiting,哪些已经 running;

· 每条请求已经计算多少 token,还需要计算多少;

· 本轮还剩多少 token budget;

· 最多还能容纳多少活动请求;

· KV Cache 是否有可复用前缀和足够的可用块;

· 请求优先级、到达顺序以及结构化输出、投机解码等附加约束。

用 token 数统一表达一轮调度

V1 会用类似下面的结构表示一轮调度结果:

{
  request_A: 1,
  request_B: 128,
  request_C: 1
}

它表示 A、B、C 三条请求在这一轮分别处理多少 token。B 可能正在处理一段 chunked prefill,A 和 C 可能正在推进 decode。数字只是示意,关键在于 V1 用“每条请求本轮处理多少 token”统一表达执行计划。

Prefill 与 Decode 的计算特征依然不同。

Prefill 可以并行处理一段 Prompt,通常更容易利用 GPU 计算能力;Decode 要逐步生成,每条请求每轮处理的 token 更少,更依赖把多条请求组成 batch。长 Prefill 如果一次占用过多资源,可能让正在生成的请求等待更久。

Sarathi-Serve[9]系统性讨论过这组吞吐与延迟矛盾,并用 chunked prefill 将长 Prompt 拆开,减少对持续 Decode 的干扰。vLLM v0.31.0 的调度行为仍以自身源码为准,但这个研究背景解释了为什么拆分 Prefill 会成为调度策略的一部分。

KV Cache 也是调度约束

请求继续计算新的 token,需要为新的 Key、Value 状态准备缓存空间。如果 KV Cache 不足,即使 GPU 还有算力,也无法无限增加活动请求。

vLLM 最初的 PagedAttention 论文[10]针对的就是 KV Cache 动态增长、内存碎片和共享效率问题。它借鉴操作系统分页,将连续的逻辑 KV Cache 映射到非连续物理块,减少预留大段连续显存造成的浪费。

在 V1 中,这件事分成两个层次:

· Scheduler 中的 KV Cache Manager 负责查询可复用前缀,并决定逻辑块的分配、释放和使用关系;

· GPU Worker 持有实际设备内存,在执行模型时读写相应 KV Cache 张量。

前者负责资源和映射决策,后者负责设备上的实际存储与计算。

调度决策与缓存约束的关系如图 6 所示。

图 6:一轮 Scheduler 决策及其缓存约束

图 6:Scheduler 根据请求状态、token budget 和 KV Cache 资源,决定每条请求在当前一轮处理多少 token。

当缓存资源不足时,部分请求可能被抢占,之后通过重新计算继续执行。V1 官方指南同时说明,旧版用于抢占的 GPU↔CPU KV Cache swapping 已经移除,因此不能继续拿早期 swap 机制解释当前默认路径。

06 GPU Worker:执行计划如何落到 GPU 上

Scheduler 给出这一轮的计算计划,模型 forward 则由执行层完成。

EngineCore 通过 Executor 调用执行后端。在本文讨论的 multiprocessing 路径中,Multiprocessing Executor[11]负责管理本地 Worker 进程,并将同一轮调用分发给对应 Worker。换成 Ray 或其他执行后端时,进程管理方式可能变化。

GPU Worker 收到的是 EngineCore 已经整理好的执行计划,不是原始 HTTP 请求。

服务启动时,Worker 会完成一组准备工作:

1. 初始化 GPU 设备与分布式通信环境;

2. 加载模型权重;

3. 通过 profiling 估算模型执行的峰值内存;

4. 根据剩余可用显存确定 KV Cache 空间;

5. 按 EngineCore 汇总后的配置初始化实际 GPU KV Cache。

gpu_worker.py[12]中的 Worker 更接近设备和生命周期管理者。真正负责组织模型输入、更新 batch 并执行 forward 的,是 GPU Model Runner。

一次执行迭代大致会经历:

· 根据 SchedulerOutput 更新本轮 batch;

· 准备 token、位置、KV Cache 映射和注意力元数据;

· 执行模型 forward;

· 完成必要的 TP、PP 通信;

· 执行采样,得到新的 token 或其他模型结果;

· 把结果交还 EngineCore。

Worker 管设备、分布式状态、模型加载和显存;Model Runner 更靠近 batch 准备、模型前向与采样。模型对象位于 Worker 一侧,并不在 API Server 进程里。

模型结果返回 EngineCore 后,Scheduler 会更新请求状态。随后,OutputProcessor[13]完成统计、增量 detokenize、停止条件处理和 RequestOutput 构造,再由 API Server 编码为流式或非流式响应。

执行与结果返回路径如图 7 所示。

图 7:执行计划进入 GPU Worker 并返回 API Server 的完整路径

图 7:SchedulerOutput 经 Executor 分发到 GPU Worker,模型结果再经过 EngineCoreOutput 和 OutputProcessor 返回 API Server。

网络层看到的一个流式 chunk 不一定严格对应一个 token。当结果生产速度快于消费者时,输出收集器可能合并增量结果;代理层和客户端 SDK 也可能改变传输粒度。

07 一次请求的完整生命周期

一条 stream=true 的 Chat Completions 请求,会依次经历这些步骤:

1. 客户端发送 messages、模型名、采样参数和流式选项。

2. API Server 完成协议校验、Chat 模板渲染、tokenization 和必要的多模态处理。

3. AsyncLLM 将输入转换为引擎内部请求,并创建异步输出收集路径。

4. EngineCoreClient 通过 ZMQ 把 EngineCoreRequest 发送到 EngineCore。

5. Scheduler 根据 token budget、请求数限制和 KV Cache,决定请求能否进入本轮以及处理多少 token。

6. EngineCore 把 SchedulerOutput 交给 Executor,GPU Worker 完成 batch 准备、模型前向和采样。

7. EngineCore 获取模型结果,Scheduler 更新请求与缓存状态;未完成的请求等待下一轮。

8. EngineCoreOutput 回到前端,OutputProcessor 完成 detokenize、停止判断并生成 RequestOutput。

9. API Server 把增量结果发送给客户端,直到请求完成、被取消或发生错误。

第 5~8 步通常会重复多次。一个 HTTP 请求只有一个开始和结束,但在它存活期间,可能穿过许多轮 Scheduler 与 Worker 执行。

请求生命周期是一条长线,EngineCore 迭代是这条长线内部不断重复的短循环。

完整时序如图 8 所示。

图 8:一条流式请求在 vLLM V1 中的完整时序

图 8:HTTP 请求只进入一次,但请求会在 EngineCore、GPU Worker 和 OutputProcessor 之间经历多轮调度、执行与增量返回。

08 从 1 卡到多卡:TP、PP、DP 怎样改变进程拓扑

按照 v0.31.0 官方架构总览[4]中的标准 GPU 部署:

· API Server 数量记为 A,使用 DP 时默认与 DP 数量一致,也可以通过 --api-server-count 调整;

· EngineCore 数量通常等于 DP;

· GPU Worker 总数 N = DP × PP × TP;

· 当 DP > 1 时,额外存在 1 个 DP Coordinator。

单 GPU 部署可以先理解成 1 个 API Server、1 个 EngineCore 和 1 个 GPU Worker。即使只有一张卡,在线服务也包含彼此分离的前端、核心控制和设备执行角色。

4 张 GPU、TP=4 时,官方示例包含 1 个 API Server、1 个 EngineCore 和 4 个 GPU Worker,共 6 个主要进程。四个 Worker 共同完成一个模型副本的执行。

8 张 GPU、TP=2、DP=4 时,官方示例包含 4 个 API Server、4 个 EngineCore、8 个 GPU Worker 和 1 个 DP Coordinator,共 17 个主要进程。每个 DP rank 对应一个 EngineCore,并管理一组 TP × PP Worker。

TP 和 DP 使用 GPU 的方式不同。TP 让多个 Worker 协作完成同一个模型副本的一轮计算,会引入更紧密的跨卡通信;DP 复制 EngineCore 和对应 Worker 组,让不同副本接收不同请求。PP 则将模型层切分到不同流水线阶段。

这些关系能解释会启动多少关键进程,却不能直接回答哪种并行方式最好。模型大小、GPU 互联、请求长度和并发模式都会影响选择。

两种典型拓扑的差异如图 9 所示。

图 9:TP=4、DP=1 与 TP=2、DP=4 的进程拓扑对比

图 9:TP=4、DP=1 使用一组四卡协同;TP=2、DP=4 则形成四个副本,每个副本由两张 GPU 协同计算。

09 vLLM 变慢时,沿请求链定位

直接修改 max-num-batched-tokens 或 gpu-memory-utilization,有时能改善结果,却很难说明问题究竟出在哪里。

更稳妥的做法,是先确定请求停在哪一段,再查看对应资源和指标。

现象
优先检查的位置
需要补充的证据
GPU 空闲但 TTFT 高
API Server、Scheduler、CPU
CPU 使用、waiting queue、调度迭代时间
KV Cache 高且出现重算
Scheduler / KV Cache
cache usage、preemption、请求长度
单卡正常,多卡变慢
Worker 间通信
NCCL、互联拓扑、各 rank 执行时间
流式输出时快时慢
调度、执行或输出路径
ITL、batch、output queue、网络
多模态请求明显更慢
输入处理或编码器
媒体加载、预处理、encoder 时间

长文本或多模态请求特别慢,同时 GPU 经常空闲,可以先看 API Server。Chat 模板、tokenization、媒体加载和预处理都会消耗 CPU;API Server CPU 饱和后,增加 GPU 并不能让请求更快进入 EngineCore。

请求已经进入 EngineCore,却长期留在 waiting 状态,需要关注 token budget、活动请求数和 KV Cache。如果缓存接近耗尽,TTFT 上升,抢占或重算增加,问题未必出在 GPU 算力。

Scheduler 能持续给出 batch,但单轮执行时间增加,排查重点就要转向 Worker 和 Model Runner:batch 形态是否变化、kernel 是否合适、CUDA Graph 是否命中、量化是否引入额外开销,以及 GPU 算力或显存带宽是否达到限制。

单卡正常、多卡扩展差,通常需要检查 Worker 之间的通信。TP 前向要求多个 rank 同步,最慢的 Worker、PCIe/NVLink 拓扑和跨节点 NCCL 都可能限制整组速度。

token 已经生成,但客户端看到的输出仍不均匀,还要检查 OutputProcessor、异步队列和网络传输。ITL 抖动可能来自模型执行,也可能来自结果聚合和客户端消费。

沿请求链的排查路径如图 10 所示。

图 10:沿请求链定位 vLLM 性能瓶颈

图 10:排查 vLLM 性能问题时,先判断请求卡在前端、IPC、调度、GPU 执行、跨卡通信还是输出路径。

沿这条请求路径排查时,各组件的边界也会变得更清楚:API Server 负责协议与输入输出,EngineCore 驱动系统,Scheduler 形成执行计划,Executor 把计划送给 Worker,GPU Model Runner 再把计划变成具体的模型前向。

最后,一次 API 调用背后的执行系统

回到开头那条迟迟没有首 token 的请求。

如果它还没有完成 tokenization 或多模态预处理,问题在 API Server 一侧;如果已经进入 EngineCore 却长期等待,要看 Scheduler 的 token 预算和 KV Cache;如果请求已经被调度,但每轮执行很慢,需要继续检查 Worker、模型计算和跨卡通信;如果 token 已经生成,客户端却收到得不均匀,还要沿 OutputProcessor 和流式返回路径继续向外查。

API Server、EngineCore、Scheduler 和 GPU Worker 共同做的,是让不断到来的请求共享有限的 CPU、显存和 GPU 计算资源,同时把每一轮结果尽快送回用户。

理解 vLLM V1,可以始终抓住两条线:

· 一条请求从进入到结束,会经过输入、调度、执行和返回;

· 请求存活期间,EngineCore 会反复完成 schedule → execute → update,让它与其他请求一起逐步向前推进。

有了这两条线,再面对 gpu-memory-utilization、max-num-batched-tokens、max-num-seqs、TP、PP 和 DP,就不再只是记参数说明。你会知道它们改变的是哪一段约束,以及为什么同一个参数可能同时影响显存容量、首 token 延迟和系统吞吐。

推荐阅读

► 从零走向 AGI 系列

► 技术专栏: 多模态大模型最新技术解读专栏 | AI 视频最新技术解读专栏 | 大模型基础入门系列专栏 | 视频内容理解技术专栏 |

参考链接

1. https://ai-mzq.github.io/From-Zero-to-AGI/:https://ai-mzq.github.io/From-Zero-to-AGI/

2. vLLM V1 官方指南:https://docs.vllm.ai/en/v0.31.0/usage/v1_guide/

3. V1 官方架构博客:https://vllm.ai/blog/2025-01-27-v1-alpha-release

4. v0.31.0 Architecture Overview:https://docs.vllm.ai/en/v0.31.0/design/arch_overview/

5. EngineCoreClient 官方 API 文档:https://docs.vllm.ai/en/v0.31.0/api/vllm/v1/engine/core_client/

6. Orca:https://www.usenix.org/conference/osdi22/presentation/yu

7. EngineCore 的 v0.31.0 源码:https://github.com/vllm-project/vllm/blob/v0.31.0/vllm/v1/engine/core.py

8. 官方调优文档:https://docs.vllm.ai/en/v0.31.0/configuration/optimization/

9. Sarathi-Serve:https://www.usenix.org/conference/osdi24/presentation/agrawal

10. PagedAttention 论文:https://arxiv.org/abs/2309.06180

11. Multiprocessing Executor:https://docs.vllm.ai/en/v0.31.0/api/vllm/v1/executor/multiproc_executor/

12. gpu_worker.py:https://github.com/vllm-project/vllm/blob/v0.31.0/vllm/v1/worker/gpu_worker.py

13. OutputProcessor:https://docs.vllm.ai/en/v0.31.0/api/vllm/v1/engine/output_processor/

【声明】内容源于网络
0
0
魔方AI空间
AI技术从业者与深耕者,专注于视觉大模型、多模态内容理解与生成、具身智能、Agent、RAG等AGI时代前沿科技成果的研究和技术分享!!
内容 206
粉丝 0
魔方AI空间 AI技术从业者与深耕者,专注于视觉大模型、多模态内容理解与生成、具身智能、Agent、RAG等AGI时代前沿科技成果的研究和技术分享!!
总阅读1.4k
粉丝0
内容206